bzoj 3653

 

每个点维护一颗以深度为下标,size-1为值的线段树,保存整颗子树的信息,这样就可以查询了,但是如果为每个节点都建立这么一颗树,显然会MLE,所以考虑在DFS序上建立主席树,然后每个节点原来对应的线段树树就是现在的两个线段树相减所得到的树。

 

  1 /**************************************************************
  2     Problem: 3653
  3     User: idy002
  4     Language: C++
  5     Result: Accepted
  6     Time:9276 ms
  7     Memory:114596 kb
  8 ****************************************************************/
  9  
 10 #include <cstdio>
 11 #define min(a,b) ((a)<(b)?(a):(b))
 12 #define N 300010
 13 #define S 6000000
 14  
 15 typedef long long dnt;
 16  
 17 struct Node {
 18     dnt v;
 19     Node *ls, *rs;
 20 }pool[S], *tail=pool, *null=tail, *root[N];
 21  
 22 int n, m;
 23 int head[N], dest[N+N], next[N+N], etot;
 24 int fat[N], dep[N], siz[N], in[N], out[N], vin[N], idc, mdep;
 25  
 26 void adde( int u, int v ) {
 27     etot++;
 28     next[etot] = head[u];
 29     dest[etot] = v;
 30     head[u] = etot;
 31 }
 32 void dfs( int u ) {
 33     idc++;
 34     in[u] = idc;
 35     vin[idc] = u;
 36     siz[u] = 1;
 37     for( int t=head[u]; t; t=next[t] ) {
 38         int v=dest[t];
 39         if( v==fat[u] ) continue;
 40         fat[v] = u;
 41         dep[v] = dep[u]+1;
 42         dfs(v);
 43         siz[u] += siz[v];
 44     }
 45     out[u] = idc;
 46     if( dep[u]>mdep ) mdep=dep[u];
 47 }
 48 inline void update( Node *nd ) {
 49     nd->v = nd->ls->v + nd->rs->v;
 50 }
 51 Node *modify( Node *snd, int lf, int rg, int pos, int delta ) {
 52     Node *nnd = ++tail;
 53     if( lf==rg ) {
 54         nnd->v = snd->v + delta;
 55         return nnd;
 56     }
 57     int mid=(lf+rg)>>1;
 58     if( pos<=mid ) {
 59         nnd->ls = modify( snd->ls, lf, mid, pos, delta );
 60         nnd->rs = snd->rs;
 61     } else {
 62         nnd->ls = snd->ls;
 63         nnd->rs = modify( snd->rs, mid+1, rg, pos, delta );
 64     }
 65     update( nnd );
 66     return nnd;
 67 }
 68 dnt query( Node *nd, int lf, int rg, int L, int R ) {
 69     if( nd==null ) return 0LL;
 70     if( L<=lf && rg<=R ) 
 71         return nd->v;
 72     int mid=(lf+rg)>>1;
 73     dnt rt = 0LL;
 74     if( L<=mid ) rt += query( nd->ls, lf, mid, L, R );
 75     if( R>mid ) rt += query( nd->rs, mid+1, rg, L, R );
 76     return rt;
 77 }
 78 void build() {
 79     null->ls = null->rs = null;
 80     null->v = 0;
 81     root[0] = null;
 82     for( int i=1; i<=idc; i++ ) {
 83         root[i] = modify( root[i-1], 1, mdep, dep[vin[i]], siz[vin[i]]-1 );
 84     }
 85 }
 86 dnt query( int u, int k ) {
 87     dnt ans1 = (dnt) min(k,dep[u]-1) * (siz[u]-1);
 88     dnt ans2 = 0LL;
 89     if( siz[u]==1 ) return ans1;
 90  
 91     ans2 += query( root[out[u]], 1, mdep, dep[u]+1, min( dep[u]+k, mdep ) );
 92     ans2 -= query( root[in[u]], 1, mdep, dep[u]+1, min( dep[u]+k, mdep ) );
 93     return ans1 + ans2;
 94 }
 95 int main() {
 96     scanf( "%d%d", &n, &m );
 97     for( int i=1,u,v; i<n; i++ ) {
 98         scanf( "%d%d", &u, &v );
 99         adde( u, v );
100         adde( v, u );
101     }
102     fat[1] = 1;
103     dep[1] = 1;
104     dfs(1);
105     build();
106     for( int t=1,u,k; t<=m; t++ ) {
107         scanf( "%d%d", &u, &k );
108         printf( "%lld\n", query(u,k) );
109     }
110 }
View Code

 

posted @ 2015-04-06 11:27  idy002  阅读(156)  评论(0编辑  收藏  举报