[BZOJ3306]树

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3306]树相关的知识,希望对你有一定的参考价值。

为什么这道题会被打上‘LCT‘的tag呢?

不管怎么说先膜LCT

如果没有过于鬼畜的艹作,查询子树有一个方法就是用数据结构维护dfs序

此题仅有单点修改,于是我们考虑用线段树维护dfs序

先以1为根dfs一次

修改->线段树单点修改

子树最小值->线段树区间查询

还有一个艹作:换根

先约定记号:[lpos[x],rpos[x]]为x的子树在dfs序中所代表的区间

假如当前查询的点为x

①若lca(x,root)!=x,这种情况下的答案与根为1是相同的,即min{lpos[x]...rpos[x]}

②若lca(x,root)==x),说明x是root的祖先,需要去掉以y为根的子树,答案为min{min{1...lpos[y]-1},min{rpos[y]+1..n}},其中y为x向root方向的儿子

技术分享

 

图画得好丑w

找y的话,找lca的时候顺便记录就好了

 

 1 #include<stdio.h>
 2 #define inf 2147483647
 3 int v[100010],h[100010],nex[200010],to[200010],lpos[100010],rpos[100010],ev[100010],dep[100010],fa[100010][18],Tmin[300010],tot,n,M,root;
 4 void add(int a,int b){
 5     tot++;
 6     to[tot]=b;
 7     nex[tot]=h[a];
 8     h[a]=tot;
 9 }
10 void dfs(int x){
11     tot++;
12     ev[tot]=v[x];
13     lpos[x]=tot;
14     for(int i=h[x];i;i=nex[i]){
15         if(to[i]!=fa[x][0]){
16             fa[to[i]][0]=x;
17             dep[to[i]]=dep[x]+1;
18             dfs(to[i]);
19         }
20     }
21     rpos[x]=tot;
22 }
23 int min(int a,int b){return a<b?a:b;}
24 void swap(int&a,int&b){a^=b^=a^=b;}
25 int lca(int x,int y){
26     if(dep[x]<dep[y])swap(x,y);
27     int i;
28     for(i=17;i>=0;i--){
29         if(dep[fa[x][i]]>dep[y])x=fa[x][i];
30     }
31     if(fa[x][0]==y)
32         return x;
33     else
34         x=fa[x][0];
35     for(i=17;i>=0;i--){
36         if(fa[x][i]!=fa[y][i]){
37             x=fa[x][i];
38             y=fa[y][i];
39         }
40     }
41     return x;
42 }
43 int query(int s,int t){
44     int ans=inf;
45     if(s>t)return ans;
46     for(s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1){
47         if(~s&1)ans=min(ans,Tmin[s^1]);
48         if(t&1)ans=min(ans,Tmin[t^1]);
49     }
50     return ans;
51 }
52 int main(){
53     int q,i,j,x,y;
54     char s[5];
55     scanf("%d%d",&n,&q);
56     root=1;
57     for(i=1;i<=n;i++){
58         scanf("%d%d",&x,v+i);
59         if(x)add(x,i);
60     }
61     tot=0;
62     dfs(1);
63     for(j=1;j<18;j++){
64         for(i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];
65     }
66     for(M=1;M<n+2;M<<=1);
67     for(i=0;i<M;i++)Tmin[i+M]=inf;
68     for(i=1;i<=n;i++)Tmin[i+M]=ev[i];
69     for(i=M-1;i>0;i--)Tmin[i]=min(Tmin[i<<1],Tmin[i<<1|1]);
70     while(q--){
71         scanf("%s",s);
72         if(s[0]==V){
73             scanf("%d%d",&x,&y);
74             i=lpos[x]+M;
75             Tmin[i]=y;
76             for(i>>=1;i;i>>=1)Tmin[i]=min(Tmin[i<<1],Tmin[i<<1|1]);
77         }
78         if(s[0]==E)scanf("%d",&root);
79         if(s[0]==Q){
80             scanf("%d",&x);
81             if(x==root){
82                 printf("%d\\n",Tmin[1]);
83                 continue;
84             }
85             y=lca(x,root);
86             if(fa[y][0]!=x)
87                 printf("%d\\n",query(lpos[x],rpos[x]));
88             else
89                 printf("%d\\n",min(query(1,lpos[y]-1),query(rpos[y]+1,n)));
90         }
91     }
92 }

 

以上是关于[BZOJ3306]树的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3306 树

[BZOJ3306]树

[BZOJ 3306]树(dfs序+线段树+倍增)

bzoj3306: 树(dfs序+倍增+线段树)

BZOJ3306: 树

[bzoj5379]Tree_dfs序_线段树_倍增lca