bzoj 3306
以1号节点为根,弄出DFS序,我们发现,对于一个询问:(rt,u),以rt为根,u节点的子树中的最小点权,我们可以根据rt,u,1这三个节点在同一条路径上的相对关系来把它转化为以1为根的在DFS序上的区间询问(中间有一种情况要在树上倍增,理解了LCA的话应该很容易写出来)。
收获:
对于只有换根这种改变树的形态的操作,又只询问和子树相关的问题,可以不用动态树。
1 /************************************************************** 2 Problem: 3306 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:2264 ms 7 Memory:19948 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <iostream> 12 #define oo 0x3f3f3f3f 13 #define N 100010 14 #define P 16 15 using namespace std; 16 17 struct Node { 18 int v; 19 Node *ls, *rs; 20 }pool[N*3], *tail=pool, *root; 21 22 int n, m; 23 int head[N], wght[N], dest[N+N], next[N+N], etot; 24 int anc[N][P+1], dep[N], in[N], out[N], vdf[N], idc; 25 26 void update( Node *nd ) { 27 nd->v = min( nd->ls->v, nd->rs->v ); 28 } 29 Node *build( int lf, int rg ) { 30 Node *nd = ++tail; 31 if( lf==rg ) { 32 nd->v = wght[vdf[lf]]; 33 return nd; 34 } 35 int mid=(lf+rg)>>1; 36 nd->ls = build( lf, mid ); 37 nd->rs = build( mid+1, rg ); 38 update( nd ); 39 return nd; 40 } 41 void modify( Node *nd, int lf, int rg, int pos, int val ) { 42 if( lf==rg ) { 43 nd->v = val; 44 return; 45 } 46 int mid=(lf+rg)>>1; 47 if( pos<=mid ) modify( nd->ls, lf, mid, pos, val ); 48 else modify( nd->rs, mid+1, rg, pos, val ); 49 update(nd); 50 } 51 int query( Node *nd, int lf, int rg, int L, int R ) { 52 if( L<=lf && rg<=R ) 53 return nd->v; 54 int mid=(lf+rg)>>1; 55 int rt = oo; 56 if( L<=mid ) rt = query( nd->ls, lf, mid, L, R ); 57 if( R>mid ) rt = min( rt, query( nd->rs, mid+1, rg, L, R ) ); 58 return rt; 59 } 60 void adde( int u, int v ) { 61 etot++; 62 next[etot] = head[u]; 63 dest[etot] = v; 64 head[u] = etot; 65 } 66 void dfs( int u ) { 67 ++idc; 68 in[u] = idc; 69 vdf[idc] = u; 70 for( int p=1; p<=P; p++ ) 71 anc[u][p] = anc[anc[u][p-1]][p-1]; 72 for( int t=head[u]; t; t=next[t] ) { 73 int v=dest[t]; 74 anc[v][0] = u; 75 dep[v] = dep[u]+1; 76 dfs(v); 77 } 78 out[u] = idc; 79 } 80 int climb( int u, int t ) { 81 for( int p=0; t; t>>=1,p++ ) 82 if( t&1 ) u=anc[u][p]; 83 return u; 84 } 85 int lca( int u, int v ) { 86 if( dep[u]<dep[v] ) swap(u,v); 87 int t=dep[u]-dep[v]; 88 u = climb( u, t ); 89 if( u==v ) return u; 90 for( int p=P; p>=0&&anc[u][0]!=anc[v][0]; p-- ) 91 if( anc[u][p]!=anc[v][p] ) u=anc[u][p],v=anc[v][p]; 92 return anc[u][0]; 93 } 94 int query( int rt, int u ) { 95 int ca=lca(rt,u); 96 if( rt==u ) { 97 return query( root, 1, idc, 1, idc ); 98 } else if( ca==u ) { 99 int ans1=oo, ans2=oo; 100 u = climb( rt, dep[rt]-dep[u]-1 ); 101 if( in[u]>=2 ) ans1 = query( root, 1, idc, 1, in[u]-1 ); 102 if( out[u]<=n-1 ) ans2 = query( root, 1, idc, out[u]+1, idc ); 103 return min( ans1, ans2 ); 104 } else { 105 return query( root, 1, idc, in[u], out[u] ); 106 } 107 } 108 int main() { 109 scanf( "%d%d", &n, &m ); 110 for( int i=1,f,w; i<=n; i++ ) { 111 scanf( "%d%d", &f, &w ); 112 wght[i] = w; 113 if( f ) adde(f,i); 114 } 115 anc[1][0] = 1; 116 dep[1] = 1; 117 dfs(1); 118 root = build( 1, idc ); 119 120 int crt=1; 121 for( int t=1,x,y; t<=m; t++ ) { 122 char ch[10]; 123 scanf( "%s", ch ); 124 125 if( ch[0]=='V' ) { 126 scanf( "%d%d", &x, &y ); 127 modify( root, 1, idc, in[x], y ); 128 } else if( ch[0]=='E' ) { 129 scanf( "%d", &crt ); 130 } else { 131 scanf( "%d", &x ); 132 printf( "%d\n", query(crt,x) ); 133 } 134 } 135 }