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 }
View Code

 

posted @ 2015-03-26 18:35  idy002  阅读(183)  评论(0编辑  收藏  举报