BZOJ 3083 遥远的国度(树链剖分+LCA)
Description
描述
zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。
问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。
Input
第1行两个整数n m,代表城市个数和操作数。
第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
第n+1行,有n个整数,代表所有点的初始防御值。
第n+2行一个整数 id,代表初始的首都为id。
第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。
Output
对于每个opt=3的操作,输出一行代表对应子树的最小点权值。
Sample Input
3 7
1 2
1 3
1 2 3
1
3 1
2 1 1 6
3 1
2 2 2 5
3 1
2 3 3 4
3 1
Sample Output
1
2
3
4
提示
对于20%的数据,n<=1000 m<=1000。
对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。
对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。
对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。
对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。
题解:首先看到路径修改和子树查询,树链剖分就没得跑了,当然也可以写LCT
操作2/3用树剖自然好写,难的是一,换根怎么看怎么尬
想了一想,如果根就是询问点,子树就是整个区间
如果根在祖先,该点的子树不变.仍是按照正规的树剖查法查
如果根在询问点的任何一个子树中,那么该询问点的子树就变成了除了这个子树之外的所有区间.
主要是如何确定这个根在哪个子树中比较麻烦,写一个类似lca的玩意,倍增记录他的祖先,到时候一点点跳上去,复杂度还是可以接受的.
我一直以为是线段树写错了,果然做题太少了orz
代码如下:
#include<cstdio> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #define lson root<<1 #define rson root<<1|1 #define inf 0x3f3f3f3f using namespace std; struct node { int lazy,m,l,r; } tr[400040]; int n,deep[100010],son[100010],fa[100010],size[100010],id[100010],top[100010],c[100010],w[100010],cnt,rt; vector<int> g[100010]; void push_up(int root) { tr[root].m=min(tr[lson].m,tr[rson].m); } void push_down(int root) { tr[lson].m=tr[root].lazy; tr[lson].lazy=tr[root].lazy; tr[rson].m=tr[root].lazy; tr[rson].lazy=tr[root].lazy; tr[root].lazy=inf; } void build(int root,int l,int r) { if(l==r) { tr[root].l=l; tr[root].r=r; tr[root].lazy=inf; tr[root].m=w[l]; return ; } int mid=(l+r)>>1; tr[root].l=l; tr[root].r=r; tr[root].lazy=inf; build(lson,l,mid); build(rson,mid+1,r); push_up(root); } void update(int root,int l,int r,int val) { if(l==tr[root].l&&r==tr[root].r) { tr[root].lazy=val; tr[root].m=val; return ; } int mid=(tr[root].l+tr[root].r)>>1; if(tr[root].lazy!=inf) { push_down(root); } if(l>mid) { update(rson,l,r,val); } else { if(r<=mid) { update(lson,l,r,val); } else { update(lson,l,mid,val); update(rson,mid+1,r,val); } } push_up(root); } int query(int root,int l,int r) { if(l>r) { return inf; } if(tr[root].l==l&&tr[root].r==r) { return tr[root].m; } int mid=(tr[root].l+tr[root].r)>>1; if(tr[root].lazy!=inf) { push_down(root); } if(l>mid) { return query(rson,l,r); } else { if(r<=mid) { return query(lson,l,r); } } return min(query(lson,l,mid),query(rson,mid+1,r)); } void dfs1(int now,int f,int dep) { deep[now]=dep; fa[now]=f; size[now]=1; int maxson=-1; for(int i=0; i<g[now].size(); i++) { if(g[now][i]==f) { continue; } dfs1(g[now][i],now,dep+1); size[now]+=size[g[now][i]]; if(size[g[now][i]]>maxson) { son[now]=g[now][i]; maxson=size[g[now][i]]; } } } void dfs2(int now,int topf) { id[now]=++cnt; w[cnt]=c[now]; top[now]=topf; if(!son[now]) { return ; } dfs2(son[now],topf); for(int i=0; i<g[now].size(); i++) { if(g[now][i]==fa[now]||g[now][i]==son[now]) { continue; } dfs2(g[now][i],g[now][i]); } } void path_update(int x,int y,int val) { while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) { swap(x,y); } update(1,id[top[x]],id[x],val); x=fa[top[x]]; } if(deep[x]>deep[y]) { swap(x,y); } update(1,id[x],id[y],val); } int sub_query(int x) { if(x==rt) { return query(1,1,cnt); } if(id[rt]<=id[x]+size[x]-1&&id[rt]>=id[x]) { return min(query(1,1,id[x]-1),query(1,id[x]+size[x],cnt)); } return query(1,id[x],id[x]+size[x]-1); } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n-1;i++) { int from,to; scanf("%d%d",&from,&to); g[from].push_back(to); g[to].push_back(from); } for(int i=1;i<=n;i++) { scanf("%d",&c[i]); } scanf("%d",&rt); dfs1(rt,0,1); dfs2(rt,rt); build(1,1,n); int kd,ll,rr,vv; for(int i=1;i<=m;i++) { scanf("%d",&kd); if(kd==1) { scanf("%d",&vv); rt=vv; } if(kd==2) { scanf("%d%d%d",&ll,&rr,&vv); path_update(ll,rr,vv); } if(kd==3) { scanf("%d",&vv); printf("%d\n",sub_query(vv)); } } }