测试地址:Tourists
题目大意:一个nnn个点m" role="presentation" style="position: relative;">mmm条边的无向连通图,每个点有点权,要求维护单点修改,还有若干次询问,每次询问两个点之间的简单路径上的点权最小值最小是多少。
做法:本题需要用到圆方树+multiset+树链剖分。
做过APIO2018-铁人两项的同学应该很快能看出来,我们实际上就是要找一个中间点,使得这个中间点的点权最小,而能作为中间点的点我们在上面那题讨论过了:路径所经过的所有点双中的点。因此我们把圆方树建出来,并把点双的信息用multiset存在方点中,然后求路径最小值就是一个裸的树链剖分了。
但是有一点要注意,如果是菊花图,那么单点修改可能会涉及到O(n)O(n)O(n)个点双,会爆,解决方法是每个点只对父亲方点有贡献,而在计算路径最小值时,如果LCA在方点上,再额外考虑它的父亲圆点即可。于是我们就以O(nlog2n)O(nlog2⁡n)O(n\log^2n)的时间复杂度解决了这一题。
(这题是十几天前写的,然而怎么都调不出来,今天发现我学了假的圆方树后赶紧改了一下,交了一发就过了……假圆方树毁一生啊……)
以下是本人代码:

#include <bits/stdc++.h>
using namespace std;
int n,m,q,w[200010];
int first[200010]={0},firstt[200010]={0},tot=0;
int tim=0,low[200010],dfn[200010],belong[200010]={0},totpbc;
int st[200010],top=0;
int fa[200010]={0},son[200010]={0},siz[200010],pos[200010],qpos[200010];
int tp[200010]={0},dep[200010]={0},seg[800010];
bool vis[200010]={0};
struct edge
{int v,next;
}e[200010],t[200010];
multiset<int> s[200010];
multiset<int>::iterator it;void insert(edge *e,int *first,int a,int b)
{e[++tot].v=b;e[tot].next=first[a];first[a]=tot;
}void init()
{scanf("%d%d%d",&n,&m,&q);for(int i=1;i<=n;i++)scanf("%d",&w[i]);for(int i=1;i<=m;i++){int a,b;scanf("%d%d",&a,&b);insert(e,first,a,b);insert(e,first,b,a);}totpbc=n;
}void tarjan(int v,int fa)
{vis[v]=1;low[v]=dfn[v]=++tim;st[++top]=v;int now=top;for(int i=first[v];i;i=e[i].next)if (e[i].v!=fa){if (!vis[e[i].v]){tarjan(e[i].v,v);low[v]=min(low[v],low[e[i].v]);if (low[e[i].v]>=dfn[v]){totpbc++;insert(t,firstt,v,totpbc);do{insert(t,firstt,totpbc,st[top]);s[totpbc].insert(w[st[top]]);belong[st[top]]=totpbc;}while(st[top--]!=e[i].v);w[totpbc]=*(s[totpbc].begin());}}else low[v]=min(low[v],dfn[e[i].v]);}
}void dfs1(int v)
{siz[v]=1;int mxsiz=0;for(int i=firstt[v];i;i=t[i].next){fa[t[i].v]=v;dep[t[i].v]=dep[v]+1;dfs1(t[i].v);if (siz[t[i].v]>mxsiz){mxsiz=siz[t[i].v];son[v]=t[i].v;}siz[v]+=siz[t[i].v];}
}void dfs2(int v,int top)
{pos[v]=++tim;qpos[tim]=v;tp[v]=top;if (son[v]) dfs2(son[v],top);for(int i=firstt[v];i;i=t[i].next)if (t[i].v!=son[v]) dfs2(t[i].v,t[i].v);
}void buildtree(int no,int l,int r)
{if (l==r){seg[no]=w[qpos[l]];return;}int mid=(l+r)>>1;buildtree(no<<1,l,mid);buildtree(no<<1|1,mid+1,r);seg[no]=min(seg[no<<1],seg[no<<1|1]);
}void segmodify(int no,int l,int r,int x,int d)
{if (l==r){seg[no]=d;return;}int mid=(l+r)>>1;if (x<=mid) segmodify(no<<1,l,mid,x,d);else segmodify(no<<1|1,mid+1,r,x,d);seg[no]=min(seg[no<<1],seg[no<<1|1]);
}int segquery(int no,int l,int r,int s,int t)
{if (l>=s&&r<=t) return seg[no];int ret=1000000000,mid=(l+r)>>1;if (s<=mid) ret=min(ret,segquery(no<<1,l,mid,s,t));if (t>mid) ret=min(ret,segquery(no<<1|1,mid+1,r,s,t));return ret;
}void modify(int x,int y)
{if (belong[x]){it=s[belong[x]].find(w[x]);s[belong[x]].erase(it);}w[x]=y;segmodify(1,1,totpbc,pos[x],y);if (belong[x]){s[belong[x]].insert(w[x]);w[belong[x]]=*(s[belong[x]].begin());segmodify(1,1,totpbc,pos[belong[x]],w[belong[x]]);}
}int query(int x,int y)
{int ret=1000000000;while(tp[x]!=tp[y]){if (dep[tp[x]]<dep[tp[y]]) swap(x,y);ret=min(ret,segquery(1,1,totpbc,pos[tp[x]],pos[x]));x=fa[tp[x]];}if (dep[x]>dep[y]) swap(x,y);ret=min(ret,segquery(1,1,totpbc,pos[x],pos[y]));if (x>n&&fa[x]) ret=min(ret,w[fa[x]]);return ret;
}void work()
{for(int i=1;i<=q;i++){char s[3];int x,y;scanf("%s%d%d",s,&x,&y);if (s[0]=='C') modify(x,y);else printf("%d\n",query(x,y));}
}int main()
{init();tot=0;tarjan(1,0);dfs1(1);tim=0;dfs2(1,1);buildtree(1,1,totpbc);work();return 0;
}

【CF487E】Tourists-圆方树+multiset+树链剖分相关推荐

  1. 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)

    题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...

  2. 洛谷P4482 [BJWC2018]Border 的四种求法 字符串,SAM,线段树合并,线段树,树链剖分,DSU on Tree...

    原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L.. ...

  3. 树链剖分之长链剖分 详解 题目整理

    树链剖分 题目中出现的树链剖分一般分为两种,重链剖分和长链剖分 重链剖分:选择子树最大的儿子, 将其归入当前点所在 的同一条重链 长链剖分:选择向下能达到的深 度最深的儿子,将其归 入当前点所在的同一 ...

  4. 【THUSC2018】史莱姆之友【长链剖分】【链分治NTT】

    不知道这题能不能发出来,如果不能请联系我,我什么都会做的 题意:给一棵 nnn 个结点的树,每个结点有个 ax+bax+bax+b,求所有根到叶子的乘积之和.系数模 99824435399824435 ...

  5. BZOJ3252攻略——长链剖分+贪心

    题目描述 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏<XX 半岛>,这款游戏有n个场景(scene),某 ...

  6. 【NOI模拟赛】纸老虎博弈(博弈论SG函数,长链剖分)

    题面 某天,C 和 K 觉得很无聊,于是决定玩一个经典小游戏: 在一棵有 nnn 个结点的有根树上,标号为 iii 的节点上有 aia_iai​ 个棋子.游戏时玩家轮流操作,每次可以将任意一个节点 u ...

  7. 【WC2010】重建计划(分数规划+长链剖分)

    长链剖分 因为有很多巨佬只是讲了一下大致的做法,并没有详细地解释如何维护,所以就有了这篇题解.巨佬们都不屑于详细写,我太弱了/kk 首先先对原树进行长链剖分. 先讲一些定义: 一条路径的权值和指的是这 ...

  8. 【CF487E】Tourists【圆方树】【树链剖分】【multiset】

    题意:给一张 nnn 点 mmm 边的连通无向图,点帯权,qqq 次操作: 修改一个点的权值. 询问两点间所有简单路的最小权值的最小值. n,m,q≤105n,m,q\leq 10^5n,m,q≤10 ...

  9. CF487E Tourists(圆方树+树链剖分)

    洛谷题目传送门 解题思路 不会圆方树的可以看我的博客圆方树学习记录及例题 首先Tarjan寻找点双连通分量,然后建立圆方树,每个方点存这个点双内的最小点权 将圆方树树链剖分之后,对于修改操作,将这个点 ...

  10. 【学习笔记】圆方树(CF487E Tourists)

    终于学了圆方树啦~\(≧▽≦)/~ 感谢y_immortal学长的博客和帮助 把他的博客挂在这里~ 点我传送到巨佬的博客QwQ! 首先我们来介绍一下圆方树能干什么呢qwq 1.将图上问题简化到树上问题 ...

最新文章

  1. Spring Autowired 注入失败总是Null
  2. linux下杀死进程的10种方法
  3. 如何蒸螃蟹?教你蒸螃蟹3个小窍门
  4. 【Qt】QWidget类详解(函数篇)
  5. React 实现 百度搜索框(简易)
  6. writing-mode属性
  7. koa2入门(3)mongoose 增删改查
  8. CF732F Tourist Reform(dfs树、边双连通图、tarjan)
  9. ABP文档 - Javascript Api - AJAX
  10. struts国际化java_java框架篇---Struts2 本地化/国际化(i18n)
  11. 二级VB培训笔记06:窗体与常用控件综合案例【个人信息注册】
  12. 【BZOJ2005】【codevs1937】能量采集,数论练习之二维公约数求和
  13. S5PV210体系结构与接口04:代码重定位 SDRAM初始化
  14. PowerShell实现“机器人定时在企业微信群中发送消息”功能(下)
  15. HDU1880 魔咒词典【文本处理】
  16. httpclient架构原理介绍 连接池详解
  17. ArcGIS超级工具目录
  18. 办公必备计算机软件,推荐8个职场办公的必备软件,每一个都能让你有所收获!...
  19. json解析天气预报java_Json解析-和风天气
  20. python 降序排列

热门文章

  1. 市场调研-全球与中国化妆品级抗坏血酸葡糖苷市场现状及未来发展趋势
  2. 数字逻辑复习——触发器
  3. JS实现网页打印功能
  4. 2019-11软考报名网站汇总,陆续更新
  5. 抖音 触摸精灵_touchscale.co在哪里玩 抖音爆火触摸称重游戏是什么
  6. idea local history说明
  7. 容器Docker学习系列五~命令学习history,save, import
  8. 8086CPU寄存器全称
  9. PeopleSoft基础知识整理
  10. 试玩网站搭建讲解入门篇