[LUOGU] P4178 Tree

用树状数组维护f前缀和,复杂度O(nlog^2n),冲榜第一

为什么大家都用的容斥、可并堆、平衡树...

#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;

inline int rd(){
    int ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

const int MAXN=200005;
const int INF=1<<29;

int n,m;

struct Edge{
    int next,to,w;
}e[MAXN<<1];
int ecnt,head[MAXN];
inline void add(int x,int y,int w){
    e[++ecnt].next = head[x];
    e[ecnt].to = y;
    e[ecnt].w = w;
    head[x] = ecnt;
}

int t[MAXN];
void update(int x,int val){
    for(int i=x;i<=m;i+=i&-i)t[i]+=val;
}
int query(int x){
    if(x==0) return 0;
    int ret=0;
    for(int i=x;i;i-=i&-i)ret+=t[i];
    return ret;
}

bool vis[MAXN];

int siz[MAXN];
void getsiz(int x,int pre){
    siz[x]=1;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(vis[v]||v==pre) continue;
        getsiz(v,x);
        siz[x]+=siz[v];
    }
}
int mn=INF,root;
void getroot(int x,int pre,int tot){
    int mx=0;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(vis[v]||v==pre) continue;
        mx=max(mx,siz[v]);
        getroot(v,x,tot);
    }
    mx=max(mx,tot-siz[x]);
    if(mx<mn) mn=mx,root=x;
}
int s[MAXN],sav[MAXN];

void dfs(int x,int pre,int dis){
    if(dis>m) return;
    s[++s[0]]=dis;sav[++sav[0]]=dis;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(vis[v]||v==pre) continue;
        dfs(v,x,dis+e[i].w);
    }
}

int ans;

void dac(int x){//Divide and Conquer :)
    sav[0]=0;mn=n;
    getsiz(x,-1);
    getroot(x,-1,siz[x]);
    int u=root;vis[u]=1;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(vis[v]) continue;
        s[0]=0;dfs(v,u,e[i].w); 
        for(int j=s[0];j>=1;j--){
            if(s[j]>m) continue;
            ans+=query(m-s[j]);
        }
        for(int j=s[0];j>=1;j--){
            if(s[j]>m) continue;
            update(s[j],1);
            ans++;
        }
    }
    for(int i=sav[0];i>=1;i--){
        if(sav[i]>m) continue;
        update(sav[i],-1);
    }
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(vis[v]) continue;
        dac(v);
    }
}
        
int main(){
    n=rd();
    int x,y,w;
    for(int i=1;i<n;i++){
        x=rd();y=rd();w=rd();
        add(x,y,w);add(y,x,w);
    }
    m=rd();
    dac(1);
    cout<<ans;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ghostcai/p/9477437.html