BZOJ 3083: 遥远的国度 [树链剖分 DFS序 LCA]
3083: 遥远的国度
Time Limit: 10 Sec Memory Limit: 1280 MBSubmit: 3127 Solved: 795
[Submit][Status][Discuss]
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
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
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。
HINT
Source
这么快A掉好高兴
没有换根,不就是dfs剖分裸题嘛?
加上换根后,发现换根后树形态不变,两点之间路径不变,并且有些子树也没变
对于询问分类讨论
x==rt 查询[1,n](注意这里要特判,一开始没有处理)
x在rt的子树内,子树没有变
x不在rt到原根的链上,子树没有变
x在rt到原根的链上,(即x=lca(x,rt)),发现现在x的子树就是整棵树减去x往rt方向向下那个节点的子树,于是倍增求那个点然后整个dfs序就是分成两段了啊
dfs的问题:没有必要出栈单独,最后一种情况就是[1,L[v]-1]和[R[v]+1,n]
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define lc o<<1 #define rc o<<1|1 #define m ((l+r)>>1) #define lson o<<1,l,m #define rson o<<1|1,m+1,r const int N=1e5+5,INF=2147483647; typedef long long ll; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} return x*f; } int n,Q,rt,w[N],fw[N],op,a,b,v; struct edge{ int v,ne; }e[N<<1]; int cnt,h[N]; inline void ins(int u,int v){ cnt++; e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt; cnt++; e[cnt].v=u;e[cnt].ne=h[v];h[v]=cnt; } int deep[N],fa[N][20],tid[N],top[N],tot,size[N],mx[N]; int L[N],R[N]; void dfs(int u){ size[u]=1; for(int i=h[u];i;i=e[i].ne){ int v=e[i].v; if(v==fa[u][0]) continue; fa[v][0]=u;deep[v]=deep[u]+1; dfs(v); size[u]+=size[v]; if(size[v]>size[mx[u]]) mx[u]=v; } } void dfs(int u,int anc){ if(!u) return; tid[u]=L[u]=++tot; top[u]=anc; for(int j=1;(1<<j)<=deep[u];j++) fa[u][j]=fa[fa[u][j-1]][j-1]; dfs(mx[u],anc); for(int i=h[u];i;i=e[i].ne) if(e[i].v!=fa[u][0]&&e[i].v!=mx[u]) dfs(e[i].v,e[i].v); R[u]=tot; } int lca(int x,int y){ while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]]) swap(x,y); x=fa[top[x]][0]; } if(deep[x]>deep[y]) swap(x,y); return x; } struct node{ int mn,set; }t[N<<2]; inline void merge(int o){ t[o].mn=min(t[lc].mn,t[rc].mn); } inline void paint(int o,int v){ t[o].mn=t[o].set=v; } inline void pushDown(int o){ if(t[o].set){ paint(lc,t[o].set); paint(rc,t[o].set); t[o].set=0; } } void build(int o,int l,int r){ if(l==r) paint(o,w[l]); else{ build(lson); build(rson); merge(o); } } void segCha(int o,int l,int r,int ql,int qr,int v){ if(ql<=l&&r<=qr) paint(o,v); else{ pushDown(o); if(ql<=m) segCha(lson,ql,qr,v); if(m<qr) segCha(rson,ql,qr,v); merge(o); } } int segQue(int o,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr) return t[o].mn; else{ pushDown(o); int mn=INF; if(ql<=m) mn=min(mn,segQue(lson,ql,qr)); if(m<qr) mn=min(mn,segQue(rson,ql,qr)); return mn; } } void change(int x,int y,int v){ while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]]) swap(x,y); segCha(1,1,n,tid[top[x]],tid[x],v); x=fa[top[x]][0]; } if(tid[x]>tid[y]) swap(x,y); segCha(1,1,n,tid[x],tid[y],v); } int jump2anc(int x,int d){ int bin=deep[x]-d; for(int j=0;j<=17;j++) if((1<<j)&bin) x=fa[x][j]; return x; } int query(int x){ if(x==rt) return segQue(1,1,n,1,n); else if(L[rt]<=tid[x]&&tid[x]<=R[rt]) return segQue(1,1,n,L[x],R[x]); else{ int p=lca(x,rt); if(x!=p) return segQue(1,1,n,L[x],R[x]); else{ int v=jump2anc(rt,deep[x]+1); return min(segQue(1,1,n,R[v]+1,n),segQue(1,1,n,1,L[v]-1)); } } } int main(){ //freopen("in.txt","r",stdin); n=read();Q=read(); for(int i=1;i<=n-1;i++) a=read(),b=read(),ins(a,b); for(int i=1;i<=n;i++) fw[i]=read(); rt=read(); dfs(rt);dfs(rt,rt); for(int i=1;i<=n;i++) w[tid[i]]=fw[i];//,printf("hi %d %d %d %d %d\n",i,tid[i],w[tid[i]],L[i],R[i]); build(1,1,n); while(Q--){ op=read(); if(op==1) rt=read(); else if(op==3) printf("%d\n",query(read())); else{ a=read();b=read();v=read(); change(a,b,v); } } }