【bzoj 3306】树
Description
给定一棵大小为 n 的有根点权树,支持以下操作:
• 换根
• 修改点权
• 查询子树最小值
Input
第一行两个整数 n, Q ,分别表示树的大小和操作数。
接下来n行,每行两个整数f,v,第i+1行的两个数表示点i的父亲和点i的权。保证f < i。如 果f = 0,那么i为根。输入数据保证只有i = 1时,f = 0。
接下来 m 行,为以下格式中的一种:
• V x y表示把点x的权改为y
• E x 表示把有根树的根改为点 x
• Q x 表示查询点 x 的子树最小值
Output
对于每个 Q ,输出子树最小值。
Sample Input
3 7
0 1
1 2
1 3
Q 1
V 1 6
Q 1
V 2 5
Q 1
V 3 4
Q 1
Sample Output
1
2
3
4
HINT
对于 100% 的数据:n, Q ≤ 10^5。
题解:
蛮裸的一道题(但我线段树打错,一路狂wa……)
跑dfs序,用线段树维护dfs序区间最值。对于x与root的关系:
1.x==root ,全局最小
2.x为root祖先节点,找到x的某个包含root的儿子,查询除去这个儿子以为的全局最值
3.其他情况下,直接查询x子树最值。
代码:
1 #include<cstdio> 2 inline int min(int a,int b){return a<b?a:b;} 3 const int N=(int )1e5+10; 4 inline int read(){ 5 int s=0,k=1;char ch=getchar(); 6 while(ch<'0'||ch>'9') k=ch=='-'?-1:k,ch=getchar(); 7 while(ch>47&&ch<='9') s=s*10+(ch^48),ch=getchar(); 8 return s*k; 9 } 10 int n,Q; 11 struct edges{ 12 int v;edges *last; 13 }edge[N],*head[N];int cnt; 14 inline void push(int u,int v){ 15 edge[++cnt]=(edges){v,head[u]};head[u]=edge+cnt; 16 } 17 struct Tree{ 18 int val;Tree *son[2]; 19 Tree(){ 20 son[0]=son[1]=NULL; 21 } 22 }tree[N<<2],*root; 23 int val[N]; 24 int rt; 25 int f[18][N],deep[N]; 26 int l[N],r[N],re[N]; 27 int num; 28 inline void dfs(int x){ 29 l[x]=++num; 30 re[num]=x; 31 for(int i=1;(1<<i)<=deep[x];i++) 32 f[i][x]=f[i-1][f[i-1][x]]; 33 for(edges *i=head[x];i;i=i->last){ 34 deep[i->v]=deep[x]+1; 35 f[0][i->v]=x; 36 dfs(i->v); 37 } 38 r[x]=num; 39 } 40 inline int LCA(int x,int y){ 41 if(deep[x]<deep[y]) x^=y^=x^=y; 42 int t=deep[x]-deep[y]; 43 for(int i=0;t;i++) if(t&(1<<i)){ 44 t^=(1<<i); 45 x=f[i][x]; 46 } 47 if(x==y) return x; 48 for(int i=16;i>=0;i--){ 49 if(f[i][x]!=f[i][y]) 50 x=f[i][x],y=f[i][y]; 51 }return f[0][x]; 52 } 53 inline void build(Tree *&u,int l,int r){ 54 u=tree+cnt; 55 cnt++; 56 if(l==r){ 57 u->val=val[re[l]];return ; 58 } 59 int mid=l+r>>1; 60 build(u->son[0],l,mid); 61 build(u->son[1],mid+1,r); 62 u->val=min(u->son[0]->val,u->son[1]->val); 63 //printf("l=%d r=%d val=%d son[0]=%d son[1]=%d\n",l,r,u->val,u->son[0]->val,u->son[1]->val); 64 } 65 66 inline void add(Tree *u,int l,int r,int x,int w){ 67 if(l==r){ 68 u->val=w;return ; 69 } 70 int mid=l+r>>1; 71 if(x>mid) add(u->son[1],mid+1,r,x,w); 72 else add(u->son[0],l,mid,x,w); 73 u->val=min(u->son[0]->val,u->son[1]->val); 74 } 75 76 inline int query(Tree *u,int l,int r,int x,int y){ 77 if(x>y) return 0x7fffffff; 78 if(x<=l&&r<=y){ 79 return u->val; 80 } 81 int mid=l+r>>1; 82 if(x>mid) return query(u->son[1],mid+1,r,x,y); 83 else if(y<=mid) return query(u->son[0],l,mid,x,y); 84 return min(query(u->son[0],l,mid,x,y),query(u->son[1],mid+1,r,x,y)); 85 } 86 int main(){ 87 n=read(),Q=read(); 88 for(int i=1;i<=n;i++){ 89 int x=read(); 90 if(x==0) rt=i; 91 val[i]=read();push(x,i); 92 } 93 dfs(rt); 94 cnt=0; 95 build(root,1,n); 96 char op[4]; 97 while(Q--){ 98 scanf("%s",op); 99 if(op[0]=='V'){ 100 int x=read(),y=read(); 101 add(root,1,n,l[x],y); 102 }else if(op[0]=='E'){ 103 int x=read(); 104 rt=x; 105 }else{ 106 int x=read(); 107 if(rt==x){ 108 printf("%d\n",root->val); 109 continue; 110 } 111 if(l[x]<=l[rt]&&r[x]>=r[rt]){ 112 int y=rt; 113 int t=deep[rt]-deep[x]-1; 114 for(int i=0;t;i++)if(t&(1<<i)){ 115 t^=1<<i; 116 y=f[i][y]; 117 } 118 printf("%d\n",min(query(root,1,n,1,l[y]-1),query(root,1,n,r[y]+1,n))); 119 }else{ 120 printf("%d\n",query(root,1,n,l[x],r[x])); 121 } 122 } 123 } 124 } 125 /* 126 3 7 127 0 1 128 1 2 129 1 3 130 Q 1 131 V 1 6 132 Q 1 133 V 2 5 134 Q 1 135 V 3 4 136 Q 1 137 */
没有什么不可能。