BZOJ 3697

http://www.lydsy.com/JudgeOnline/problem.php?id=3697

点分治

休息站在起点到根的路径上或根到终点的路径上。

dfs时记录下路径的树上前缀和x,并判断路径的前缀和为x的节点。

枚举根的每个子树。

用g[i][0/1],f[i][0/1]分别表示已访问过的子树以及现在的子树和为i的路径数目,

0和1用于区分路径上是否存在前缀和为i的节点.

当前子树对答案的贡献为f[0][0]*g[0][0]+Σ(f[i][0]*g[-i][1]+f[i][1]*g[-i][0]+f[i][1]*g[-i][1]).

 
#include<cstdio>
#define FOR(i,s,t) for(register int i=s;i<=t;++i) 
#define gc getchar()
inline int max(int a,int b){return a>b?a:b;}
typedef long long ll;
ll ans;
inline int read(){
    char c;while(c=gc,c==' '||c=='\n');int data=c-48;
    while(c=gc,c>='0'&&c<='9')data=(data<<1)+(data<<3)+c-48;return data;
}
const int N=800011;
struct edge{
    int to,w;
    edge *nxt;
    #define to(it) it->to
    #define w(it) it->w 
    #define add(x,y,z) (*++et=(edge){y,z,las[x]},las[x]=et)
    #define VIS(now) for(edge *it=las[now];it;it=it->nxt)
}e[N>>1],*las[N>>2],*et=e;  
int f[N][2],g[N][2],t[N];
int sz[N],p[N];
bool vis[N];
int n,x,y,z,G,sum,maxdeep;
inline void getG(int now,int fa){
    sz[now]=1,p[now]=0;
    VIS(now)
        if(to(it)!=fa&&!vis[to(it)]){
            getG(to(it),now);
            sz[now]+=sz[to(it)];
            p[now]=max(p[now],sz[to(it)]);
        }
    p[now]=max(p[now],sum-sz[now]);
    if(p[now]<p[G])G=now;
}
inline void dfs(int now,int fa,int len,int dep){
    maxdeep=max(maxdeep,dep);
    t[len+n]?++g[len+n][1]:++g[len+n][0];
    ++t[len+n];
    VIS(now)
        if(to(it)!=fa&&!vis[to(it)])
            dfs(to(it),now,len+w(it),dep+1); 
    --t[len+n];
}
inline void solve(int now){
    vis[now]=1;f[n][0]=1;
    int S=sum,mx=0;
    VIS(now)
        if(!vis[to(it)]){
            maxdeep=1;
            dfs(to(it),0,w(it),1);
            ans+=1ll*g[n][0]*(f[n][0]-1);
            mx=max(mx,maxdeep);
            FOR(i,-maxdeep,maxdeep)
                ans+=1ll*g[n-i][1]*f[n+i][1]+1ll*g[n-i][0]*f[n+i][1]+1ll*g[n-i][1]*f[n+i][0];
            FOR(i,-maxdeep,maxdeep){
                f[i+n][0]+=g[i+n][0];
                f[i+n][1]+=g[i+n][1];
                g[i+n][0]=g[i+n][1]=0;
            }
        }
    FOR(i,n-mx,n+mx)
        f[i][0]=f[i][1]=0;
    VIS(now)
        if(!vis[to(it)]){
            G=0;
            sum=sz[to(it)];
            getG(to(it),0);
            solve(G);
        }
}
int main(){
    n=read();
    FOR(i,2,n){
        x=read();y=read();z=read();
        if(!z)z=-1;
        add(x,y,z);add(y,x,z);
    }
    sum=p[0]=n;
    getG(1,0);
    solve(G);
    printf("%lld\n",ans);
    return 0;
}

  

posted @ 2017-12-06 20:22  Stump  阅读(204)  评论(0编辑  收藏  举报