bzoj 3653

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

 /**************************************************************
Problem: 3653
User: idy002
Language: C++
Result: Accepted
Time:9276 ms
Memory:114596 kb
****************************************************************/ #include <cstdio>
#define min(a,b) ((a)<(b)?(a):(b))
#define N 300010
#define S 6000000 typedef long long dnt; struct Node {
dnt v;
Node *ls, *rs;
}pool[S], *tail=pool, *null=tail, *root[N]; int n, m;
int head[N], dest[N+N], next[N+N], etot;
int fat[N], dep[N], siz[N], in[N], out[N], vin[N], idc, mdep; void adde( int u, int v ) {
etot++;
next[etot] = head[u];
dest[etot] = v;
head[u] = etot;
}
void dfs( int u ) {
idc++;
in[u] = idc;
vin[idc] = u;
siz[u] = ;
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t];
if( v==fat[u] ) continue;
fat[v] = u;
dep[v] = dep[u]+;
dfs(v);
siz[u] += siz[v];
}
out[u] = idc;
if( dep[u]>mdep ) mdep=dep[u];
}
inline void update( Node *nd ) {
nd->v = nd->ls->v + nd->rs->v;
}
Node *modify( Node *snd, int lf, int rg, int pos, int delta ) {
Node *nnd = ++tail;
if( lf==rg ) {
nnd->v = snd->v + delta;
return nnd;
}
int mid=(lf+rg)>>;
if( pos<=mid ) {
nnd->ls = modify( snd->ls, lf, mid, pos, delta );
nnd->rs = snd->rs;
} else {
nnd->ls = snd->ls;
nnd->rs = modify( snd->rs, mid+, rg, pos, delta );
}
update( nnd );
return nnd;
}
dnt query( Node *nd, int lf, int rg, int L, int R ) {
if( nd==null ) return 0LL;
if( L<=lf && rg<=R )
return nd->v;
int mid=(lf+rg)>>;
dnt rt = 0LL;
if( L<=mid ) rt += query( nd->ls, lf, mid, L, R );
if( R>mid ) rt += query( nd->rs, mid+, rg, L, R );
return rt;
}
void build() {
null->ls = null->rs = null;
null->v = ;
root[] = null;
for( int i=; i<=idc; i++ ) {
root[i] = modify( root[i-], , mdep, dep[vin[i]], siz[vin[i]]- );
}
}
dnt query( int u, int k ) {
dnt ans1 = (dnt) min(k,dep[u]-) * (siz[u]-);
dnt ans2 = 0LL;
if( siz[u]== ) return ans1; ans2 += query( root[out[u]], , mdep, dep[u]+, min( dep[u]+k, mdep ) );
ans2 -= query( root[in[u]], , mdep, dep[u]+, min( dep[u]+k, mdep ) );
return ans1 + ans2;
}
int main() {
scanf( "%d%d", &n, &m );
for( int i=,u,v; i<n; i++ ) {
scanf( "%d%d", &u, &v );
adde( u, v );
adde( v, u );
}
fat[] = ;
dep[] = ;
dfs();
build();
for( int t=,u,k; t<=m; t++ ) {
scanf( "%d%d", &u, &k );
printf( "%lld\n", query(u,k) );
}
}
上一篇:LDAP实例异常停止日志提示虚拟内存virtual memory不足


下一篇:http://blog.csdn.net/dyllove98/article/details/7706218