洛谷P3899 [湖南集训]谈笑风生(线段树合并)

为了学长链剖分开的题,结果还是忍不住写了个线段树合并

首先不难发现:$b$ 要么是 $a$ 的祖先,要么是 $a$ 的后代。

$b$ 是 $a$ 的祖先很好弄,因为 $c$ 的数量始终等于 $size_a-1$;对于 $b$ 要么是 $a$ 的后代的情况,那么就是求 $a$ 的子树中和它深度差不超过 $k$ 的点的 $size-1$ 之和,按照深度插进线段树以后合并一下即可。

#include<cstdio>
#include<vector>
#define For(i,A,B) for(i=(A);i<=(B);++i)
using namespace std;
typedef long long ll;
const int N=300050;
const int BUF=1<<21;
char rB[BUF],*rS,*rT,wB[BUF+50];
int wp=-1;
inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,BUF,stdin),rS==rT)?EOF:*rS++;}
inline void flush(){fwrite(wB,1,wp+1,stdout);wp=-1;}
inline int rd(){
    char c=gc();
    while(c<48||c>57)c=gc();
    int x=c&15;
    for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15);
    return x;
}
short buf[25];
inline void wt(ll x){
    if(wp>BUF)flush();
    short l=-1;
    while(x>9){
        buf[++l]=x%10;
        x/=10;
    }
    wB[++wp]=x|48;
    while(l>=0)wB[++wp]=buf[l--]|48;
    wB[++wp]='\n';
}
int G[N],to[N<<1],nxt[N<<1],sz,dep[N],siz[N],rt[N],lc[N*20],rc[N*20],tot,n;
ll sum[N*20],s[N];
vector<int> k[N],id[N];
inline int Min(int a,int b){return a<b?a:b;}
inline void adde(int u,int v){
    to[++sz]=v;nxt[sz]=G[u];G[u]=sz;
    to[++sz]=u;nxt[sz]=G[v];G[v]=sz;
}
void add(int &o,int L,int R,int x,int k){
    if(!o)o=++tot;
    sum[o]+=k;
    if(L<R){
        int M=L+R>>1;
        if(x<=M)add(lc[o],L,M,x,k);
        else add(rc[o],M+1,R,x,k);
    }
}
int merg(int u,int v){
    if(!u||!v)return u|v;
    sum[u]+=sum[v];
    lc[u]=merg(lc[u],lc[v]);rc[u]=merg(rc[u],rc[v]);
    return u;
}
ll query(int o,int L,int R,int x,int y){
    if(!o)return 0ll;
    if(x<=L&&y>=R)return sum[o];
    int M=L+R>>1;
    ll ans=0ll;
    if(x<=M)ans=query(lc[o],L,M,x,y);
    if(y>M)ans+=query(rc[o],M+1,R,x,y);
    return ans;
}
void dfs(int u,int fa){
    int i,v;
    dep[u]=dep[fa]+1;
    siz[u]=1;
    for(i=G[u];i;i=nxt[i])if((v=to[i])!=fa){
        dfs(v,u);
        rt[u]=merg(rt[u],rt[v]);
        siz[u]+=siz[v];
    }
    For(i,0,(int)k[u].size()-1)s[id[u][i]]=query(rt[u],1,n,dep[u]+1,Min(n,dep[u]+k[u][i]))+(ll)Min(dep[u]-1,k[u][i])*(siz[u]-1);
    add(rt[u],1,n,dep[u],siz[u]-1);
}
int main(){
    int q,i,u,v;
    n=rd();q=rd();
    For(i,2,n){
        u=rd();v=rd();
        adde(u,v);
    }
    For(i,1,q){
        u=rd();v=rd();
        k[u].push_back(v);id[u].push_back(i);
    }
    dfs(1,0);
    For(i,1,q)wt(s[i]);
    flush();
    return 0;
}
View Code

 

posted @ 2020-03-15 12:50  wangyuchen  阅读(194)  评论(0编辑  收藏  举报