阴阳

来源:互联网 发布:php const调用赋值 编辑:程序博客网 时间:2024/05/17 05:50

Description

给出一棵n个点的树,每条边有边权1或-1.一条合法的路径(st,en)指路径上存在一个异于端点的点x,使得dis(st,x)=dis(x,en)=0.(dis不解释),求合法路径的数量。
n<=10^5

Solution

学习(复习)点分治
考虑经过当前重心x的合法路径,可以发现,满足这样的路径都是dis(st,x)+dis(x,en)=0且st到x的路径中有一个点k满足dis(k,x)=dis(st,x),或en到x的路径中有这样的点。
那我们可以处理出所有的d[i]表示dis(x,i),然后开一个桶来计算它可以和多少对点配对。
设bz[i]=1表示i到x的路径中有一个点k满足d[k]=d[i],那么
当bz[i]=1&d[i]=0时,i点可以和x配对。
所有d[i]=0的点都可以互相配对。
细节特别多(纯粹来练练手)

Code

#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define rep(i,a) for(int i=last[a];i;i=next[i])#define N 100005using namespace std;typedef long long ll;struct note{int v,s,x;}d[N];bool cmp(note x,note y) {return x.s<y.s;}int n,l,x,y,z,tot,dis[N],size[N],yes[N],no[N],p[N*2];int t[N*2],next[N*2],v[N*3],last[N];bool bz[N];ll ans;void add(int x,int y,int z) {    t[++l]=y;v[l]=z;next[l]=last[x];last[x]=l;}void get_size(int x,int y) {    size[x]=1;    rep(i,x) if (!bz[t[i]]&&t[i]!=y) {        get_size(t[i],x);        size[x]+=size[t[i]];    }}void get_heavy(int x,int y) {    bool f=0;    rep(i,x) if (!bz[t[i]]&&t[i]!=y) {        get_heavy(t[i],x);        if (size[t[i]]>tot/2) f=1;    }    if (tot-size[x]>tot/2) f=1;    if (!f) z=x;}void get_ans(int x,int y) {    if (!dis[x]&&p[N]) ans++;    ans+=yes[N-dis[x]];    if (p[N+dis[x]]) ans+=no[N-dis[x]];    p[N+dis[x]]++;    rep(i,x) if (t[i]!=y&&!bz[t[i]]) {        dis[t[i]]=dis[x]+v[i];        get_ans(t[i],x);    }    p[N+dis[x]]--;}void updata(int x,int y) {    if (!dis[x]||p[N+dis[x]]) yes[N+dis[x]]++;    else no[N+dis[x]]++;    p[N+dis[x]]++;    rep(i,x) if (t[i]!=y&&!bz[t[i]]) updata(t[i],x);    p[N+dis[x]]--;}void clear(int x,int y) {    yes[dis[x]+N]=no[dis[x]+N]=0;    rep(i,x) if (!bz[t[i]]&&t[i]!=y) clear(t[i],x);}void dfs(int x) {    get_size(x,0);tot=size[x];    get_heavy(x,0);bz[z]=1;    rep(i,z) if (!bz[t[i]]) {        dis[t[i]]=v[i];        get_ans(t[i],z);        updata(t[i],z);    }    clear(z,0);    rep(i,z) if (!bz[t[i]]) dfs(t[i]);}int main() {    scanf("%d",&n);    fo(i,1,n-1) {        scanf("%d%d%d",&x,&y,&z);        if (!z) z=-1;        add(x,y,z);add(y,x,z);    }    dfs(1);    printf("%lld",ans);}
0 0