BZOJ 3083 遥远的国度(树链剖分)

3083: 遥远的国度

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 5003  Solved: 1434
[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提供

题解:

这题有换根操作,但按照普通的思路我们可以发现,换根之后树的形态会有改变,每个节点的子树会发生改变,所以我们来分类讨论。

修改链的操作不会发生改变,现在只考虑子树minn。为了方便,我们定义现在的换的“根节点”为root(但实际上树的根节点为1),子树根为x,黑圈标明查询范围;

情况一   x=root,很显然此时应当查询整棵树。

 

 

情况二 lca(root,x)!=x ,此时直接查询x的子树即可,与换根无关。

 

情况三,lca(root,x)=x,此时我们应当查询与x相邻的节点中与root最近的点v在整棵树中的补集

 

可以发现v一定在root到x的链上,且一定是x在这条链上的儿子,倍增法可以求得v

BZOJ TLE也返回RE???  用普通树剖一直RE,用倍增就过了Orz.

参考代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define clr(a,b) memset(a,b,sizeof (a))
  4 #define PI acos(-1.0)
  5 typedef long long ll;
  6 const int maxn=2e5+10;
  7 const int INF=0x3f3f3f3f;
  8 /*首先有一个整数opt如果opt=1接下来有一个整数id代表把首都修改
  9 为id如果opt=2接下来有三个整数p1 p2 v代表将p1 p2路径上的所有
 10 城市的防御值修改为v如果opt=3接下来有一个整数 id代表询问以城
 11 市id为根的子树中的最小防御值*/
 12 int n,m,op,xx,yy,zz,a[maxn],head[maxn];
 13 int siz[maxn],son[maxn],fa[maxn],top[maxn],deep[maxn];
 14 int tid[maxn],rnk[maxn],f[maxn][20],cnt,tot;
 15 struct Edge{
 16     int v,nxt;
 17 } edge[maxn<<1];
 18 void addedge(int x,int y) 
 19 {
 20     edge[tot].v=y;
 21     edge[tot].nxt=head[x];
 22     head[x]=tot++;
 23 }
 24 
 25 inline void dfs1(int x)
 26 {
 27     siz[x]=1; 
 28     for(int i=1;i<=19;++i) { if((1<<i)<=deep[x]) f[x][i]=f[f[x][i-1]][i-1];else break;  }
 29     for(int i=head[x];~i;i=edge[i].nxt)
 30     {
 31         int v=edge[i].v;
 32         if(v!=fa[x]) 
 33         {
 34             fa[v]=f[v][0]=x;
 35             deep[v]=deep[x]+1;
 36             dfs1(v);
 37             siz[x]+=siz[v];
 38             if(son[x]==-1||siz[son[x]]<siz[v]) son[x]=v; 
 39         }
 40     }
 41 }
 42 
 43 inline void dfs2(int x,int tp)
 44 {
 45     tid[x]=++cnt;rnk[cnt]=x;top[x]=tp;
 46     if(son[x]==-1) return;
 47     dfs2(son[x],tp);
 48     for(int i=head[x];~i;i=edge[i].nxt)
 49     {
 50         int v=edge[i].v;
 51         if(v!=fa[x]&&v!=son[x]) dfs2(v,v);
 52     }
 53 
 54 }
 55 
 56 struct Tree{
 57     int l,r,min_num;
 58     int tag;
 59 } tree[maxn<<4];
 60 
 61 inline void pushup(int rt)
 62 {
 63     tree[rt].min_num=min(tree[rt<<1].min_num,tree[rt<<1|1].min_num);
 64 }
 65 inline void pushdown(int rt)
 66 {
 67     tree[rt<<1].tag=tree[rt<<1|1].tag=tree[rt].tag;
 68     tree[rt<<1].min_num=tree[rt<<1|1].min_num=tree[rt].tag;
 69     tree[rt].tag=-1;
 70 }
 71 
 72 inline void Build(int rt,int l,int r)
 73 {
 74     tree[rt].l=l,tree[rt].r=r;tree[rt].tag=-1;
 75     if(l==r){ tree[rt].min_num=a[rnk[l]]; return ;}
 76     int mid=l+r>>1;
 77     Build(rt<<1,l,mid);Build(rt<<1|1,mid+1,r);
 78     pushup(rt);
 79 }
 80 
 81 inline void Insert(int rt,int L,int R,int val)//1
 82 {
 83     if(tree[rt].l>=L&&tree[rt].r<=R){tree[rt].min_num=tree[rt].tag=val;return;}
 84     if(~tree[rt].tag) pushdown(rt);
 85     int mid=(tree[rt].l+tree[rt].r)>>1;
 86     if(R<=mid) Insert(rt<<1,L,R,val);
 87     else if(L>=mid+1) Insert(rt<<1|1,L,R,val); 
 88     else Insert(rt<<1,L,mid,val),Insert(rt<<1|1,mid+1,R,val);
 89     pushup(rt);
 90 }
 91 //1和2用倍增来把x~y的值变为val 
 92 inline void Update(int x,int y,int val)//2
 93 {
 94     int fx=top[x],fy=top[y];
 95     while(fx!=fy)
 96     {
 97         if(deep[fx]<deep[fy]) swap(x,y),swap(fx,fy);
 98         Insert(1,tid[fx],tid[x],val);
 99         x=fa[fx],fx=top[x];
100     }
101     if(deep[x]>deep[y]) swap(x,y);
102     Insert(1,tid[x],tid[y],val);
103 }
104 
105 inline int Query(int rt,int L,int R)
106 {
107     if(tree[rt].l>=L&&tree[rt].r<=R) return tree[rt].min_num;
108     if(~tree[rt].tag) pushdown(rt);
109     int mid=tree[rt].l+tree[rt].r>>1;
110     if(R<=mid) return Query(rt<<1,L,R);
111     else if(L>=mid+1) return Query(rt<<1|1,L,R);
112     else return min(Query(rt<<1,L,mid),Query(rt<<1|1,mid+1,R));    
113 } 
114 
115 inline int LCA(int x,int y)
116 {
117     int fx=top[x],fy=top[y];
118     while(fx!=fy)
119     {
120         if(deep[fx]<deep[fy]) swap(x,y),swap(fx,fy);
121         x=fa[fx],fx=top[x];
122     }
123     return deep[x]>deep[y] ? y:x;
124 }
125 
126 inline void Init()
127 {
128     clr(head,-1);clr(son,-1);
129     clr(f,0);cnt=0;tot=1;
130 }
131 int main()
132 {
133     Init();int root;deep[1]=1;
134     scanf("%d%d",&n,&m);
135     for(int i=1;i<n;++i) scanf("%d%d",&xx,&yy),addedge(xx,yy),addedge(yy,xx);
136     for(int i=1;i<=n;++i) scanf("%d",&a[i]);
137     dfs1(1),dfs2(1,1);Build(1,1,n);
138     scanf("%d",&root);
139     while(m--)
140     {
141         scanf("%d%d",&op,&xx);
142         if(op==1) root=xx;
143         else if(op==2) { scanf("%d%d",&yy,&zz),Update(xx,yy,zz); }
144         else
145         {
146             if(root==xx) { printf("%d\n",tree[1].min_num);continue;}
147             int lca=LCA(xx,root);
148             if(xx!=lca) printf("%d\n",Query(1,tid[xx],tid[xx]+siz[xx]-1));
149             else
150             {
151                 int tmp=deep[root]-deep[xx]-1,ans=INF;yy=root;
152                 for(int i=0;i<=19;++i) if((1<<i)&tmp) yy=f[yy][i];
153                 if(tid[yy]>1) ans=Query(1,1,tid[yy]-1);
154                 if(tid[yy]+siz[yy]<=n) ans=min(ans,Query(1,tid[yy]+siz[yy],n));
155                 printf("%d\n",ans);
156             }
157         }
158     }
159     return 0;
160 }
161 /*
162 3 7
163 1 2
164 1 3
165 1 2 3
166 1
167 3 1
168 2 1 1 6
169 3 1
170 2 2 2 5
171 3 1
172 2 3 3 4
173 3 1
174 */
View Code

 

  

posted @ 2018-10-30 00:01  StarHai  阅读(336)  评论(0编辑  收藏  举报