【bzoj3083】遥远的国度(树链剖分+线段树)
题目描述
zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。
问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。
RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。
由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。
输入输出格式
输入格式:
第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为根的子树中的最小防御值。
输出格式:
对于每个opt=3的操作,输出一行代表对应子树的最小点权值。
输入输出样例
说明
对于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
然后发现没法维护子树信息,决定每一个点开一棵平衡树,后来发现空间要爆……
于是好好学了一下正解
首先查询和修改路径都是树剖的基本操作这里不提
然后现在最重要的是换根操作咋整
我们考虑一下,当前根与点$x$在原树中的关系无非以下几种:
1.当前根就是点$x$——那么直接输出整棵树答案就行了
2.当前根在原树中不在$x$的子树内——那么哪怕根换成了现在的根,$x$的子树还是没有变化,那么我们可以直接去原来的子树里查询
3.当前根在原树中在$x$的子树内——那么我们设当前根在$u$点的子树$v$内,那么所要求的答案就是整棵树除去$v$这一棵子树的答案。至于怎么求$v$,可以从$root$往上跳重链,直到跳到$u$为止,那么就是看它从哪一个$u$点的子节点跳过来的就好了
因为读入进来的时候路径端点和更改的值弄错了……而且忘记找$v$了……调了半天
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #define int unsigned int 5 using namespace std; 6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 7 char buf[1<<21],*p1=buf,*p2=buf; 8 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} 9 inline int read(){ 10 #define num ch-'0' 11 char ch;bool flag=0;int res; 12 while(!isdigit(ch=getc())) 13 (ch=='-')&&(flag=true); 14 for(res=num;isdigit(ch=getc());res=res*10+num); 15 (flag)&&(res=-res); 16 #undef num 17 return res; 18 } 19 char sr[1<<21],z[30];int C=-1,Z; 20 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 21 inline void print(int x){ 22 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 23 while(z[++Z]=x%10+48,x/=10); 24 while(sr[++C]=z[Z],--Z);sr[++C]='\n'; 25 } 26 const int N=100005,inf=0xffffffff; 27 int head[N],Next[N<<1],ver[N<<1],tot; 28 int fa[N],dep[N],son[N],sz[N],top[N],ls[N],rs[N],cnt; 29 int v[N],mn[N<<2],tag[N<<2]; 30 int n,m,rt; 31 inline void add(int u,int v){ 32 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 33 ver[++tot]=u,Next[tot]=head[v],head[v]=tot; 34 } 35 void dfs1(int u){ 36 sz[u]=1,dep[u]=dep[fa[u]]+1; 37 for(int i=head[u];i;i=Next[i]){ 38 int v=ver[i]; 39 if(v!=fa[u]){ 40 fa[v]=u,dfs1(v),sz[u]+=sz[v]; 41 if(sz[v]>sz[son[u]]) son[u]=v; 42 } 43 } 44 } 45 void dfs2(int u,int t){ 46 top[u]=t,ls[u]=++cnt; 47 if(son[u]){ 48 dfs2(son[u],t); 49 for(int i=head[u];i;i=Next[i]){ 50 int v=ver[i]; 51 if(v!=fa[u]&&v!=son[u]) dfs2(v,v); 52 } 53 } 54 rs[u]=cnt; 55 } 56 inline void pushup(int p){mn[p]=min(mn[p<<1],mn[p<<1|1]);} 57 inline void pushdown(int p){ 58 if(tag[p]) 59 mn[p<<1]=mn[p<<1|1]=tag[p<<1]=tag[p<<1|1]=tag[p],tag[p]=0; 60 } 61 void build(int p,int l,int r){ 62 if(l==r) return (void)(mn[p]=v[l]); 63 int mid=l+r>>1; 64 build(p<<1,l,mid),build(p<<1|1,mid+1,r); 65 pushup(p); 66 } 67 void update(int p,int l,int r,int ql,int qr,int x){ 68 if(ql<=l&&qr>=r) return (void)(mn[p]=tag[p]=x); 69 pushdown(p); 70 int mid=l+r>>1; 71 if(ql<=mid) update(p<<1,l,mid,ql,qr,x); 72 if(qr>mid) update(p<<1|1,mid+1,r,ql,qr,x); 73 pushup(p); 74 } 75 int query(int p,int l,int r,int ql,int qr){ 76 if(ql<=l&&qr>=r) return mn[p]; 77 pushdown(p); 78 int mid=l+r>>1,ans=inf; 79 if(ql<=mid) cmin(ans,query(p<<1,l,mid,ql,qr)); 80 if(qr>mid) cmin(ans,query(p<<1|1,mid+1,r,ql,qr)); 81 return ans; 82 } 83 int find(int t,int u){ 84 while(top[u]!=top[t]){ 85 if(fa[top[u]]==t) return top[u]; 86 u=fa[top[u]]; 87 } 88 return son[t]; 89 } 90 void modify(int u,int v,int x){ 91 while(top[u]!=top[v]){ 92 if(dep[top[u]]<dep[top[v]]) swap(u,v); 93 update(1,1,n,ls[top[u]],ls[u],x),u=fa[top[u]]; 94 } 95 if(dep[u]>dep[v]) swap(u,v); 96 update(1,1,n,ls[u],ls[v],x); 97 } 98 signed main(){ 99 //freopen("testdata.in","r",stdin); 100 n=read(),m=read(); 101 for(int i=1;i<n;++i){ 102 int u=read(),v=read();add(u,v); 103 } 104 dfs1(1),dfs2(1,1); 105 for(int i=1;i<=n;++i) v[ls[i]]=read(); 106 build(1,1,n); 107 rt=read(); 108 while(m--){ 109 int opt=read(),x=read(),y,z; 110 switch(opt){ 111 case 1:rt=x;break; 112 case 2:y=read(),z=read(),modify(x,y,z);break; 113 case 3:{ 114 if(ls[rt]==ls[x]) print(mn[1]); 115 else if(ls[rt]<ls[x]||ls[rt]>rs[x]) print(query(1,1,n,ls[x],rs[x])); 116 else{ 117 int res=inf,t=find(x,rt); 118 if(ls[t]>1) cmin(res,query(1,1,n,1,ls[t]-1)); 119 if(rs[t]<n) cmin(res,query(1,1,n,rs[t]+1,n)); 120 print(res); 121 } 122 break; 123 } 124 } 125 } 126 Ot(); 127 return 0; 128 }