BZOJ3306: 树
n<=1e5的有根点权树,m<=1e5个操作:换根,修改点权,查询子树最小值。
维护子树信息--dfs序,至于换根只需要分类讨论一下现在根和查询点的关系。
如果查询的点是根节点,就输出整颗树的最小值。
如果查询的点5在1到7的路径上,那以7为根的时候查询5,就是整颗树排除粉红色部分--5的儿子中,是7的祖先的那棵子树,就是5的儿子中能走到7的那一个对应的子树。
其他情况,直接输出查询的子树。
所以再写一个lca就行了,这里写了链剖可以顺便把dfs序搞出来。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 //#include<assert.h> 5 #include<math.h> 6 #include<algorithm> 7 //#include<iostream> 8 using namespace std; 9 10 int n,m; 11 #define maxn 200011 12 struct Edge{int to,next;}edge[maxn<<1];int first[maxn],val[maxn],le=2; 13 void in(int x,int y) {Edge &e=edge[le];e.to=y;e.next=first[x];first[x]=le++;} 14 void insert(int x,int y) {in(x,y);in(y,x);} 15 int size[maxn],hea[maxn],fa[maxn],top[maxn],dep[maxn],list[maxn],lp[maxn],rp[maxn],ll; 16 void dfs1(int x,int f) 17 { 18 fa[x]=f;dep[x]=dep[f]+1; 19 size[x]=1;hea[x]=0; 20 for (int i=first[x];i;i=edge[i].next) 21 { 22 const Edge &e=edge[i];if (e.to==f) continue; 23 dfs1(e.to,x); 24 size[x]+=size[e.to]; 25 if (size[hea[x]]<size[e.to]) hea[x]=e.to; 26 } 27 } 28 void dfs2(int x,int from) 29 { 30 top[x]=from; 31 list[++ll]=x;lp[x]=ll; 32 if (hea[x]) dfs2(hea[x],from); 33 for (int i=first[x];i;i=edge[i].next) 34 { 35 const Edge &e=edge[i];if (e.to==hea[x] || e.to==fa[x]) continue; 36 dfs2(e.to,e.to); 37 } 38 rp[x]=ll; 39 } 40 void treecut() 41 { 42 dep[0]=fa[0]=size[0]=ll=0; 43 dfs1(1,0); 44 dfs2(1,1); 45 } 46 int lca(int x,int y) 47 { 48 while (top[x]!=top[y]) 49 { 50 if (dep[top[x]]<dep[top[y]]) {int t=x;x=y;y=t;} 51 x=fa[top[x]]; 52 } 53 return dep[x]<dep[y]?x:y; 54 } 55 int findimp(int x,int y) 56 { 57 int last; 58 while (top[x]!=top[y]) 59 { 60 last=top[y]; 61 y=fa[top[y]]; 62 } 63 if (x==y) return last; 64 return list[lp[x]+1]; 65 } 66 struct SMT 67 { 68 struct Node 69 { 70 int Min; 71 int l,r; 72 int ls,rs; 73 }a[maxn<<1]; 74 int size; 75 SMT() {size=0;} 76 void up(int x) 77 { 78 const int &p=a[x].ls,&q=a[x].rs; 79 a[x].Min=min(a[p].Min,a[q].Min); 80 } 81 void build(int &x,int L,int R) 82 { 83 x=++size; 84 a[x].l=L;a[x].r=R; 85 if (L==R) 86 { 87 a[x].Min=val[list[L]]; 88 a[x].ls=a[x].rs=0; 89 } 90 else 91 { 92 const int mid=(L+R)>>1; 93 build(a[x].ls,L,mid); 94 build(a[x].rs,mid+1,R); 95 up(x); 96 } 97 } 98 void build() {int x;build(x,1,n);} 99 int ql,qr,v; 100 void be(int x) 101 { 102 if (a[x].l==a[x].r && a[x].l==ql) {a[x].Min=v;return;} 103 const int mid=(a[x].l+a[x].r)>>1; 104 if (ql<=mid) be(a[x].ls); 105 else be(a[x].rs); 106 up(x); 107 } 108 void be(int x,int v) 109 { 110 ql=x;this->v=v; 111 be(1); 112 } 113 int query(int x) 114 { 115 if (ql<=a[x].l && a[x].r<=qr) return a[x].Min; 116 const int mid=(a[x].l+a[x].r)>>1; 117 int ans=0x3f3f3f3f; 118 if (ql<=mid) ans=min(ans,query(a[x].ls)); 119 if (qr> mid) ans=min(ans,query(a[x].rs)); 120 return ans; 121 } 122 int query(int L,int R) 123 { 124 if (L>R) return 0x3f3f3f3f; 125 ql=L;qr=R; 126 return query(1); 127 } 128 }t; 129 int nowroot; 130 int main() 131 { 132 scanf("%d%d",&n,&m); 133 int x,y;char s[3]; 134 memset(first,0,sizeof(first)); 135 for (int i=1;i<=n;i++) 136 { 137 scanf("%d%d",&x,&y); 138 if (x) insert(x,i); 139 val[i]=y; 140 } 141 treecut(); 142 t.build(); 143 nowroot=1; 144 while (m--) 145 { 146 scanf("%s",s); 147 if (s[0]=='E') scanf("%d",&nowroot); 148 else if (s[0]=='V') scanf("%d%d",&x,&y),t.be(lp[x],y); 149 else if (s[0]=='Q') 150 { 151 scanf("%d",&x); 152 if (x==nowroot) printf("%d\n",t.query(1,n)); 153 else 154 { 155 int l=lca(x,nowroot); 156 if (l==nowroot || (l!=x && l!=nowroot)) printf("%d\n",t.query(lp[x],rp[x])); 157 else 158 { 159 int tmp=findimp(x,nowroot); 160 printf("%d\n",min(t.query(1,lp[tmp]-1),t.query(rp[tmp]+1,n))); 161 } 162 } 163 } 164 } 165 return 0; 166 } 167