hdu 4918
第一道树的点分治。
感谢:
http://blog.csdn.net/u013368721/article/details/40887575
首先,找出原图的重心(最大子树大小最小的点(如果作为根)),去掉它后原图就分成了若干的森林,再在对应的森林中找出重心,递归这个过程(只有一个点时返回)。
这样,我们就可以根据重心的所属关系,建立出一棵树,显然原图的重心就是这颗树的重心,每个重心对应一些点(就是去掉该重心前,该重心联通块中的所有点)。
容易看出,因为每次选的是重心,所以树每次至少会分成两块(最坏情况),考虑我们根据重心所属关系建立出的树,最多有O(logn)层,每层找重心总的复杂度是O(n)(因为每层重心对应的点是O(n)级别的),所以建立这个关系是O(nlogn)的复杂度。
应前辈的称呼,我们就叫建立出的这颗很多重心的树为重心树。
对于这道题,我们可以给重心树的每个节点建立一个树状数组,树状数组下标为到重心的距离,值为点的权值,将重心对应的点都放到这个树状数组中(因为最大距离就是该重心对应的点数-1,所以树状数组的大小就设成该重心对应的点数),因为一层对应的所有重心对应的点数最多为O(n),所以总共占用的空间为O(nlogn)。然后还要根据这个重心的不同子重心分开记录一下这个东西,用于去重。
1 #include <cstdio> 2 #include <vector> 3 #include <map> 4 #define N 100010 5 using namespace std; 6 7 struct Stat { 8 int r, d, s; 9 Stat( int r, int d, int s ):r(r),d(d),s(s){} 10 }; 11 struct Bit { 12 int n; 13 vector<int> vv; 14 void init( int n ) { 15 this->n = n; 16 vv.resize( n+1 ); 17 for( int t=1; t<=n; t++ ) vv[t] = 0; 18 } 19 void modify( int pos, int delta ) { 20 pos++; 21 for( int i=pos; i<=n; i+=i&-i ) 22 vv[i]+=delta; 23 } 24 int query( int pos ) { 25 int rt = 0; 26 pos++; 27 if( pos>n ) pos=n; 28 for( int i=pos; i; i-=i&-i ) 29 rt += vv[i]; 30 return rt; 31 } 32 }; 33 34 int n, m; 35 vector<int> g[N]; 36 vector<Stat> st[N]; 37 map<int,Bit > bit[N]; 38 int ww[N]; 39 int vis[N], siz[N], anc[N], bac[N], dis[N]; 40 int qu[N], beg, tail; 41 42 void init( int n ) { 43 for( int i=1; i<=n; i++ ) { 44 g[i].clear(); 45 st[i].clear(); 46 bit[i].clear(); 47 vis[i] = false; 48 } 49 } 50 void build( int root ) { 51 qu[beg=tail=0] = root; 52 anc[root] = root; 53 siz[root] = bac[root] = 0; 54 while( tail>=beg ) { 55 int u=qu[beg++]; 56 for( int t=0; t<g[u].size(); t++ ) { 57 int v=g[u][t]; 58 if( v==anc[u] || vis[v] ) continue; 59 qu[++tail] = v; 60 anc[v] = u; 61 siz[v] = bac[v] = 0; 62 } 63 } 64 for( int i=tail; i; i-- ) { 65 int v=qu[i]; 66 int u=anc[v]; 67 siz[v]++; 68 siz[u]+=siz[v]; 69 if( siz[v]>bac[u] ) bac[u]=siz[v]; 70 } 71 for( int i=0; i<=tail; i++ ) { 72 int u = qu[i]; 73 if( siz[root]-siz[u]>bac[u] ) bac[u]=siz[root]-siz[u]; 74 } 75 for( int i=0; i<=tail; i++ ) { 76 int u = qu[i]; 77 if( bac[u]<bac[root] ) root=u; 78 } 79 //---------------- found the core -------------------// 80 bit[root][0].init( tail+1 ); 81 bit[root][0].modify( 0, ww[root] ); 82 st[root].push_back( Stat(root,0,0) ); 83 vis[root] = true; 84 85 86 anc[root] = root; 87 for( int t=0; t<g[root].size(); t++ ) { 88 int sr = g[root][t]; 89 if( vis[sr] ) continue; 90 qu[beg=tail=0] = sr; 91 dis[sr] = 1; 92 anc[sr] = root; 93 while( tail>=beg ) { 94 int u=qu[beg++]; 95 for( int t=0; t<g[u].size(); t++ ) { 96 int v=g[u][t]; 97 if( vis[v] || v==anc[u] ) continue; 98 qu[++tail] = v; 99 dis[v] = dis[u]+1; 100 anc[v] = u; 101 } 102 } 103 bit[root][sr].init( tail+2 ); 104 for( int i=0; i<=tail; i++ ) { 105 int u=qu[i]; 106 bit[root][0].modify( dis[u], ww[u] ); 107 bit[root][sr].modify( dis[u], ww[u] ); 108 st[u].push_back( Stat(root,dis[u],sr) ); 109 } 110 } 111 for( int t=0; t<g[root].size(); t++ ) { 112 int v=g[root][t]; 113 if( vis[v] ) continue; 114 build(g[root][t]); 115 } 116 } 117 void modify( int u, int d ) { 118 for( int t=0; t<st[u].size(); t++ ) { 119 Stat &s = st[u][t]; 120 bit[s.r][0].modify( s.d, d ); 121 if( s.s ) bit[s.r][s.s].modify( s.d, d ); 122 } 123 } 124 int query( int u, int d ) { 125 int rt = 0; 126 for( int t=0; t<st[u].size(); t++ ) { 127 Stat &s = st[u][t]; 128 if( d<s.d ) continue; 129 int v = bit[s.r][0].query( d-s.d ); 130 rt += v; 131 if( s.s ) { 132 v = bit[s.r][s.s].query( d-s.d ); 133 rt -= v; 134 } 135 } 136 return rt; 137 } 138 139 int main() { 140 while(1) { 141 if( scanf( "%d%d", &n, &m )!=2 ) return 0; 142 init(n); 143 for( int i=1; i<=n; i++ ) 144 scanf( "%d", ww+i ); 145 for( int i=1,u,v; i<n; i++ ) { 146 scanf( "%d%d", &u, &v ); 147 g[u].push_back( v ); 148 g[v].push_back( u ); 149 } 150 build(1); 151 for( int i=1; i<=m; i++ ) { 152 char ch[10]; 153 int u, d; 154 scanf( "%s%d%d", ch, &u, &d ); 155 if( ch[0]=='!' ) { 156 modify( u, d-ww[u] ); 157 ww[u] = d; 158 } else { 159 printf( "%d\n", query(u,d) ); 160 } 161 } 162 } 163 }