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
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。
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。
题解Here!
三种操作:换根,区间修改,子树最小值。
如果没有换根,这就是一道树剖的沙茶题。
但是有换根呢?
我们仍然以$1$为根建树。
然后我们分类讨论一下:
1. 如果$now==root$ ,那就是查询整棵树 ,直接输出$queryunderline min(1,n)$就好了。
2. 如果$LCA(now,root)!=now$,这时根与$now$没有关系,直接查询$now$的子树即可。
3. 如果$LCA(now,root)==now$,这时比较麻烦。
我们可以先找一下$now$的所有儿子。
由于一个子树的$dfs$序是连续的。
所以,如果这个儿子的$id$小于等于$id[root]$,并且这个子树中的最大$dfs$序($id[son]+size[son]-1$)大于等于当前的$id[root]$。
那么就可以判断出$root$在这个儿子中或者就是这个儿子,记录下这个儿子。
还是那句话 :一个子树的$dfs$序是连续的。
这时$now$的子树就是去除包含$root$的那个儿子的子树的整棵树了。
当然,这题也可以用$LCT$维护子树信息做,只不过我不会啊。。。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #define LSON rt<<1 #define RSON rt<<1|1 #define DATA(x) b[x].data #define SIGN(x) b[x].c #define LSIDE(x) b[x].l #define RSIDE(x) b[x].r #define WITDH(x) (RSIDE(x)-LSIDE(x)+1) #define MAXN 100010 #define MAX (1LL<<62) using namespace std; int n,m,c=1,d=1,root; int val[MAXN],head[MAXN],deep[MAXN],son[MAXN],size[MAXN],fa[MAXN],id[MAXN],pos[MAXN],top[MAXN]; struct Tree{ int next,to; }a[MAXN<<1]; struct Segmeng_Tree{ long long data,c; int l,r; }b[MAXN<<2]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline void pushup(int rt){ DATA(rt)=min(DATA(LSON),DATA(RSON)); } inline void pushdown(int rt){ if(SIGN(rt)==-1||LSIDE(rt)==RSIDE(rt))return; SIGN(LSON)=DATA(LSON)=SIGN(rt); SIGN(RSON)=DATA(RSON)=SIGN(rt); SIGN(rt)=-1; } void buildtree(int l,int r,int rt){ LSIDE(rt)=l;RSIDE(rt)=r;SIGN(rt)=-1; if(l==r){ DATA(rt)=val[pos[l]]; return; } int mid=l+r>>1; buildtree(l,mid,LSON); buildtree(mid+1,r,RSON); pushup(rt); } void update(int l,int r,long long c,int rt){ if(l<=LSIDE(rt)&&RSIDE(rt)<=r){ SIGN(rt)=DATA(rt)=c; return; } pushdown(rt); int mid=LSIDE(rt)+RSIDE(rt)>>1; if(l<=mid)update(l,r,c,LSON); if(mid<r)update(l,r,c,RSON); pushup(rt); } long long query(int l,int r,int rt){ long long ans=MAX; if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt); pushdown(rt); int mid=LSIDE(rt)+RSIDE(rt)>>1; if(l<=mid)ans=min(ans,query(l,r,LSON)); if(mid<r)ans=min(ans,query(l,r,RSON)); return ans; } inline void add(int x,int y){ a[c].to=y;a[c].next=head[x];head[x]=c++; a[c].to=x;a[c].next=head[y];head[y]=c++; } void dfs1(int rt){ son[rt]=0;size[rt]=1; for(int i=head[rt];i;i=a[i].next){ int will=a[i].to; if(!deep[will]){ deep[will]=deep[rt]+1; fa[will]=rt; dfs1(will); size[rt]+=size[will]; if(size[son[rt]]<size[will])son[rt]=will; } } } void dfs2(int rt,int f){ id[rt]=d++;pos[id[rt]]=rt;top[rt]=f; if(son[rt])dfs2(son[rt],f); for(int i=head[rt];i;i=a[i].next){ int will=a[i].to; if(will!=fa[rt]&&will!=son[rt])dfs2(will,will); } } 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]]; } if(deep[x]>deep[y])swap(x,y); return x; } void solve_update(int x,int y,int k){ while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]])swap(x,y); update(id[top[x]],id[x],k,1); x=fa[top[x]]; } if(deep[x]>deep[y])swap(x,y); update(id[x],id[y],k,1); } void solve_query(int x){ if(x==root)printf("%lld ",query(1,n,1)); else{ int lca=LCA(x,root); if(lca==x){ int y; for(int i=head[x];i;i=a[i].next){ int will=a[i].to; if(id[will]<=id[root]&&id[root]<=id[will]+size[will]-1){y=will;break;} } long long s=min(query(1,id[y]-1,1),query(id[y]+size[y],n,1)); printf("%lld ",s); } else printf("%lld ",query(id[x],id[x]+size[x]-1,1)); } } void work(){ int f,x,y,k; while(m--){ f=read();x=read(); if(f==1){ root=x; } else if(f==2){ y=read();k=read(); solve_update(x,y,k); } else solve_query(x); } } void init(){ int x,y; n=read();m=read(); for(int i=1;i<n;i++){ x=read();y=read(); add(x,y); } for(int i=1;i<=n;i++)val[i]=read(); root=read(); deep[1]=1; dfs1(1); dfs2(1,1); buildtree(1,n,1); } int main(){ init(); work(); return 0; }