bzoj 1468
大概思路:树点分治,重心树中每个重心维护一个总的平衡树,树中保存属于该重心的点到该重心的距离,然后对于去掉该重心后形成的子树分别再保存一份。
用这种方式实现的话,还可以支持修改与多次查询,每次操作都是O(logn*logn)
感悟:
点分治正如一个前辈说的,是“借助”重心的力量,来维护与查询与某点距离相关的问题,我们知道点u到它各个重心的距离关系,各个重心又保存了所有属于它的点的信息,可以证明,一个点至多属于O(logn)个重心,所有重心拥有的点总和为O(nlogn)。
本质上来说,树的点分治是通过找重心来对树分治,然后建立了一种层次关系(想象一下,找出一棵树的重心,然后在3维空间向上提升,幷让重心向剩下的各块的重心连边,然后再将各块分层,这样就形成了这种层次关系,表现为树结构就是所谓的重心树)。
1 /************************************************************** 2 Problem: 1468 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:6536 ms 7 Memory:54384 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <vector> 12 #include <map> 13 #define fprintf(...) 14 #define N 40010 15 #define S 2000000 16 using namespace std; 17 18 struct Stat { 19 int c, d, s; 20 Stat( int c, int d, int s ):c(c),d(d),s(s){} 21 }; 22 struct Splay { 23 static int son[S][2], pre[S], key[S], siz[S], ntot; 24 int root; 25 void init() { root=0; } 26 inline void update( int nd ) { 27 siz[nd] = siz[son[nd][0]]+siz[son[nd][1]]+1; 28 } 29 void rotate( int nd, int d ) { 30 int p=pre[nd]; 31 int s=son[nd][!d]; 32 int ss=son[s][d]; 33 34 son[nd][!d] = ss; 35 son[s][d] = nd; 36 if( p ) son[p][ nd==son[p][1] ] = s; 37 else root = s; 38 39 pre[nd] = s; 40 pre[s] = p; 41 if( ss ) pre[ss] = nd; 42 43 update( nd ); 44 update( s ); 45 } 46 void splay( int nd, int top=0 ) { 47 while( pre[nd]!=top ) { 48 int p = pre[nd]; 49 int nl = nd==son[p][0]; 50 if( pre[p]==top ) { 51 rotate( p, nl ); 52 } else { 53 int pp = pre[p]; 54 int pl = p==son[pp][0]; 55 if( nl==pl ) { 56 rotate( pp, pl ); 57 rotate( p, nl ); 58 } else { 59 rotate( p, nl ); 60 rotate( pp, pl ); 61 } 62 } 63 } 64 } 65 int newnode( int p, int k ) { 66 int nd = ++ntot; 67 son[nd][0] = son[nd][1] = 0; 68 pre[nd] = p; 69 key[nd] = k; 70 siz[nd] = 1; 71 return nd; 72 } 73 void insert( int k ) { 74 if( !root ) { 75 root = newnode( 0, k ); 76 return; 77 } 78 int nd = root; 79 while( son[nd][ k>key[nd] ] ) nd=son[nd][ k>key[nd] ]; 80 son[nd][ k>key[nd] ] = newnode( nd, k ); 81 splay( son[nd][ k>key[nd] ] ); 82 } 83 int query( int k ) { 84 int nd=root; 85 int lnd; 86 int rt = 0; 87 while(nd) { 88 lnd = nd; 89 if( key[nd]>k ) { 90 nd = son[nd][0]; 91 } else { 92 rt += siz[son[nd][0]]+1; 93 nd = son[nd][1]; 94 } 95 } 96 splay( lnd ); 97 return rt; 98 } 99 }; 100 int Splay::son[S][2], Splay::pre[S], Splay::key[S], Splay::siz[S], Splay::ntot; 101 102 103 int n, qdis; 104 vector<int> g[N], ww[N]; 105 vector<Stat> st[N]; 106 map<int,Splay > spy[N]; 107 int vis[N], anc[N], siz[N], bac[N], dis[N]; 108 int qu[N], bg, ed; 109 110 void build( int rt ) { 111 /* find the core of the block containing rt */ 112 qu[bg=ed=1] = rt; 113 anc[rt] = rt; 114 siz[rt] = bac[rt] = 0; 115 while( ed>=bg ) { 116 int u=qu[bg++]; 117 for( int t=0; t<g[u].size(); t++ ) { 118 int v=g[u][t]; 119 if( vis[v] || v==anc[u] ) continue; 120 qu[++ed] = v; 121 anc[v] = u; 122 siz[v] = bac[v] = 0; 123 } 124 } 125 for( int i=ed; i>=1; i-- ) { 126 int u=qu[i]; 127 int p=anc[u]; 128 siz[u]++; 129 siz[p] += siz[u]; 130 if( bac[p]<siz[u] ) bac[p]=siz[u]; 131 } 132 for( int i=ed; i>=1; i-- ) { 133 int u=qu[i]; 134 if( bac[u]<siz[rt]-siz[u] ) bac[u]=siz[rt]-siz[u]; 135 } 136 for( int i=ed; i>=1; i-- ) { 137 int u=qu[i]; 138 if( bac[u]<bac[rt] ) rt=u; 139 } 140 /* statistics the info of the block */ 141 spy[rt][0].init(); 142 spy[rt][0].insert( 0 ); 143 st[rt].push_back( Stat(rt,0,0) ); 144 vis[rt] = true; 145 fprintf( stderr, "%d as core\n", rt ); 146 for( int tm=0; tm<g[rt].size(); tm++ ) { 147 int r=g[rt][tm], w=ww[rt][tm]; 148 if( vis[r] ) continue; 149 qu[bg=ed=1] = r; 150 anc[r] = rt; 151 dis[r] = w; 152 while( ed>=bg ) { 153 int u=qu[bg++]; 154 for( int t=0; t<g[u].size(); t++ ) { 155 int v=g[u][t], w=ww[u][t]; 156 if( vis[v] || v==anc[u] ) continue; 157 qu[++ed] = v; 158 anc[v] = u; 159 dis[v] = dis[u]+w; 160 } 161 } 162 spy[rt][r].init(); 163 for( int i=ed; i>=1; i-- ) { 164 int u=qu[i]; 165 spy[rt][0].insert( dis[u] ); 166 spy[rt][r].insert( dis[u] ); 167 st[u].push_back( Stat(rt,dis[u],r) ); 168 } 169 build( r ); 170 } 171 } 172 173 int main() { 174 scanf( "%d", &n ); 175 for( int i=1,u,v,w; i<n; i++ ) { 176 scanf( "%d%d%d", &u, &v, &w ); 177 g[u].push_back( v ); 178 g[v].push_back( u ); 179 ww[u].push_back( w ); 180 ww[v].push_back( w ); 181 } 182 scanf( "%d", &qdis ); 183 build(1); 184 for( int u=1; u<=n; u++ ) { 185 fprintf( stderr, "Stat of %d:\n", u ); 186 for( int t=0; t<st[u].size(); t++ ) { 187 fprintf( stderr, "core=%d dis=%d subcore:%d\n", st[u][t].c, st[u][t].d, st[u][t].s ); 188 } 189 fprintf( stderr, "\n" ); 190 } 191 192 int ans = 0; 193 for( int u=1; u<=n; u++ ) { 194 int tans=0; 195 for( int t=0; t<st[u].size(); t++ ) { 196 Stat &s = st[u][t]; 197 tans += spy[s.c][0].query( qdis-s.d )- (s.s?spy[s.c][s.s].query( qdis-s.d ):0); 198 } 199 fprintf( stderr, "%d added %d\n", u, tans-1 ); 200 ans += tans-1; 201 } 202 printf( "%d\n", ans/2 ); 203 }