「BZOJ3083」遥远的国度(树剖换根
3083: 遥远的国度
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 4859 Solved: 1372
[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
zhonghaoxi提供
题解
我也是有B站账号的女人了!
这道题除了换根以外就很板子了,——所以我们聊聊换根。
首先在原根下建出一棵树,设当前的根为root。
对于子树k的操作:
1.root==k 那么对整棵树操作。
2.lca(root,k)!=k 也就是说root对k并没有什么影响,直接操作k。
3.lca(root,k)==k root在k的子树中,想象一下揪着一根毛拿起一顶假发......
那么对整个树中,除了原根意义下 k的儿子中含root的那一股 以外,的整棵树操作。
(也可以认为对整个树操作,然后对root那一股撤销操作
其实,所谓的换根操作,并不是要你每次把树再重新建一遍(复杂度起飞
而是考你分类讨论的能力QAQ
——
然后,一定一定要注意边界啊!字母不要混用啊!QAQ
以及 鉴于数据极接近maxint,不如直接longlong2333
1 /************************************************************** 2 Problem: 3083 3 User: qwerta 4 Language: C++ 5 Result: Accepted 6 Time:5528 ms 7 Memory:55532 kb 8 ****************************************************************/ 9 10 #include<algorithm> 11 #include<iostream> 12 #include<cstdio> 13 #include<cmath> 14 using namespace std; 15 #define R register 16 const int MAXN=100007; 17 struct emm{ 18 int e,f; 19 }b[2*MAXN]; 20 int h[MAXN]; 21 int tot=0; 22 void con(int u,int v) 23 { 24 b[++tot].f=h[u]; 25 h[u]=tot; 26 b[tot].e=v; 27 b[++tot].f=h[v]; 28 h[v]=tot; 29 b[tot].e=u; 30 return; 31 } 32 int d[MAXN],fa[MAXN],top[MAXN],siz[MAXN],z[MAXN]; 33 void dfs(int x) 34 { 35 siz[x]=1,top[x]=x; 36 int mac=0,macc=-1; 37 for(R int i=h[x];i;i=b[i].f) 38 if(!d[b[i].e]) 39 { 40 d[b[i].e]=d[x]+1; 41 fa[b[i].e]=x; 42 dfs(b[i].e); 43 siz[x]+=siz[b[i].e]; 44 if(macc<siz[b[i].e]){mac=b[i].e,macc=siz[b[i].e];} 45 } 46 z[x]=mac; 47 top[mac]=x; 48 return; 49 } 50 int q[MAXN],dfn[MAXN]; 51 void dfss(int x) 52 { 53 q[++tot]=x; 54 dfn[x]=tot; 55 if(z[x])dfss(z[x]); 56 for(R int i=h[x];i;i=b[i].f) 57 if(d[b[i].e]==d[x]+1&&b[i].e!=z[x]) 58 dfss(b[i].e); 59 return; 60 } 61 int val[MAXN]; 62 int fitop(int x) 63 { 64 if(top[x]==x)return x; 65 return top[x]=fitop(top[x]); 66 } 67 struct ahh{ 68 int l,r,mid; 69 long long v,laz; 70 }a[16*MAXN]; 71 #define lz (i<<1) 72 #define rz ((i<<1)|1) 73 #define md a[i].mid 74 void build(int i,int ll,int rr) 75 { 76 a[i].l=ll; 77 a[i].r=rr; 78 if(ll==rr){a[i].v=val[q[ll]];return;} 79 md=(ll+rr)>>1; 80 build(lz,ll,md); 81 build(rz,md+1,rr); 82 a[i].v=min(a[lz].v,a[rz].v); 83 return; 84 } 85 int k; 86 void pushtag(int i)//啰嗦的pushtag 87 { 88 if(!a[i].laz)return; 89 a[i].v=a[i].laz; 90 if(a[i].l!=a[i].r) 91 { 92 a[lz].v=a[lz].laz=a[i].laz; 93 a[rz].v=a[rz].laz=a[i].laz; 94 } 95 a[i].laz=0; 96 return; 97 } 98 void change(int i,int ll,int rr) 99 { 100 pushtag(i);//覆盖操作可不像累加有交换律啊!修改也要pushtagQAQ 101 if(a[i].l==ll&&a[i].r==rr){a[i].v=a[i].laz=k;return;} 102 if(rr<=md)change(lz,ll,rr); 103 else if(md+1<=ll)change(rz,ll,rr); 104 else {change(lz,ll,md);change(rz,md+1,rr);} 105 a[i].v=min(a[lz].v,a[rz].v);//记得一路更新上去QAQ 106 return; 107 } 108 long long ans; 109 void find(int i,int ll,int rr) 110 { 111 pushtag(i); 112 if(a[i].l==ll&&a[i].r==rr){ans=min(ans,a[i].v);return;} 113 if(rr<=md)find(lz,ll,rr); 114 else if(md+1<=ll)find(rz,ll,rr); 115 else {find(lz,ll,md);find(rz,md+1,rr);} 116 a[i].v=min(a[lz].v,a[rz].v); 117 return; 118 } 119 int filca(int u,int v) 120 { 121 while(top[u]!=top[v]) 122 { 123 if(d[top[u]]<d[top[v]])swap(u,v); 124 u=fa[top[u]]; 125 } 126 if(d[u]<d[v])swap(u,v); 127 return v; 128 } 129 int main() 130 { 131 //freopen("a.in","r",stdin); 132 int n,m; 133 scanf("%d%d",&n,&m); 134 for(R int i=1;i<n;++i) 135 { 136 int u,v; 137 scanf("%d%d",&u,&v); 138 con(u,v); 139 } 140 for(R int i=1;i<=n;++i) 141 scanf("%d",&val[i]); 142 int s; 143 scanf("%d",&s); 144 d[s]=1; 145 dfs(s); 146 tot=0; 147 dfss(s); 148 for(R int i=1;i<=n;++i) 149 top[i]=fitop(i); 150 build(1,1,n); 151 int rot=s; 152 for(R int ew=1;ew<=m;++ew)//顺手打i->疯狂WA 153 { 154 int opt; 155 scanf("%d",&opt); 156 if(opt==1) 157 { 158 int id; 159 scanf("%d",&id); 160 rot=id; 161 } 162 else if(opt==2) 163 { 164 int u,v; 165 scanf("%d%d%d",&u,&v,&k); 166 while(top[u]!=top[v]) 167 { 168 if(d[top[u]]<d[top[v]])swap(u,v); 169 change(1,dfn[top[u]],dfn[u]); 170 u=fa[top[u]]; 171 } 172 if(d[u]<d[v])swap(u,v); 173 change(1,dfn[v],dfn[u]); 174 } 175 else 176 { 177 int x; 178 scanf("%d",&x); 179 ans=999999999999; 180 if(rot==x) 181 find(1,dfn[s],dfn[s]+siz[s]-1); 182 else 183 { 184 int lca=filca(rot,x); 185 if(lca!=x) 186 find(1,dfn[x],dfn[x]+siz[x]-1); 187 else 188 { 189 for(R int i=h[x];i;i=b[i].f) 190 if(d[b[i].e]==d[x]+1) 191 { 192 if(dfn[b[i].e]<=dfn[rot]&&dfn[b[i].e]+siz[b[i].e]-1>=dfn[rot]) 193 { 194 find(1,1,dfn[b[i].e]-1); 195 if(dfn[b[i].e]+siz[b[i].e]<=n)//不注意边界->疯狂RE 196 find(1,dfn[b[i].e]+siz[b[i].e],n); 197 } 198 } 199 } 200 } 201 printf("%lld\n",ans); 202 } 203 } 204 return 0; 205 } 206
把AC率丢到地上蹂躏.jpg