「BZOJ3083」遥远的国度(树剖换根

3083: 遥远的国度

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 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

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。

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
",ans);
202         }
203     }
204     return 0;
205 }
206 

把AC率丢到地上蹂躏.jpg

原文地址:https://www.cnblogs.com/qwerta/p/9656629.html