1. 程式人生 > >「FJ2014集訓 采藥人的路徑」

「FJ2014集訓 采藥人的路徑」

std include += truct new stream 路徑 判斷 不存在

題目

考慮一下把\(0\)看成\(-1\),那麽就是找到一條邊權和為\(0\)的路徑,且這條路徑可以被分成兩段,邊權和都是\(0\)

沒有第二個限制就是點分裸題了

其實有了第二個限制還是點分裸題

考慮那個斷點肯定會存在於當前分治重心的某一邊,或者直接在分治重心上,我們在求每個點到分治重心的距離的時候判斷一下上面能否有一個點成為斷點就好了

具體做法就是開個桶,判斷每個點的祖先是否有一個和它的分治重心的距離相等

之後就把點分成了兩類,一類是到分治重心的路徑上存在斷點,一類是不存在的,顯然不存在的只能和存在的拼成路徑,同時還要滿足距離和加起來為\(0\)就好了

於是開兩個桶分別維護一下就好了

代碼

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define LL long long
#define re register
#define maxn 100005
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
struct E{int v,nxt,w;}e[maxn<<1];
int n,m,num,now,rt,S;LL ans;
int head[maxn],sum[maxn],mx[maxn],vis[maxn],pre[maxn];
int f[maxn<<1],tax[maxn<<1][2],top[2],st[maxn<<1][2];
inline void add(int x,int y,int z) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;e[num].w=z;}
void getroot(int x,int fa) {
    sum[x]=1,mx[x]=0;
    for(re int i=head[x];i;i=e[i].nxt) {
        if(vis[e[i].v]||e[i].v==fa) continue;
        getroot(e[i].v,x);sum[x]+=sum[e[i].v];
        mx[x]=max(mx[x],sum[e[i].v]);
    }
    mx[x]=max(mx[x],S-sum[x]);
    if(mx[x]<now) rt=x,now=mx[x];
}
void getdis(int x,int fa,int o) {
    pre[x]=pre[fa]+o;
    if(f[pre[x]+n]) {
        st[++top[1]][1]=x;
        if(f[pre[x]+n]>1&&pre[x]==0) ans++;
    }
        else st[++top[0]][0]=x;
    f[pre[x]+n]++;
    for(re int i=head[x];i;i=e[i].nxt) {
        if(vis[e[i].v]||e[i].v==fa) continue;
        getdis(e[i].v,x,e[i].w);
    }
    f[pre[x]+n]--;
}
void clear(int x,int fa) {
    tax[n+pre[x]][0]=tax[n+pre[x]][1]=0;pre[x]=0;
    for(re int i=head[x];i;i=e[i].nxt) {
        if(vis[e[i].v]||e[i].v==fa) continue;
        clear(e[i].v,x);
    }
}
void dfs(int x) {
    vis[x]=1;f[0+n]=1;
    for(re int i=head[x];i;i=e[i].nxt) {
        if(vis[e[i].v]) continue;
        top[0]=top[1]=0;getdis(e[i].v,x,e[i].w);
        for(re int j=1;j<=top[0];j++) 
            ans+=tax[n-pre[st[j][0]]][1];
        for(re int j=1;j<=top[1];j++) 
            ans+=tax[n-pre[st[j][1]]][1]+tax[n-pre[st[j][1]]][0];
        for(re int j=1;j<=top[0];j++) tax[n+pre[st[j][0]]][0]++;
        for(re int j=1;j<=top[1];j++) tax[n+pre[st[j][1]]][1]++;
    }f[0+n]=0;
    for(re int i=head[x];i;i=e[i].nxt) {
        if(vis[e[i].v]) continue;
        clear(e[i].v,x);
    }
    for(re int i=head[x];i;i=e[i].nxt) {
        if(vis[e[i].v]) continue;
        S=sum[e[i].v],now=n,getroot(e[i].v,0),dfs(rt);
    }
}
int main() {
    n=read();
    for(re int x,y,z,i=1;i<n;i++) {
        x=read(),y=read(),z=read();
        if(!z) z=-1;add(x,y,z),add(y,x,z);
    }
    now=n,S=n,getroot(1,0);dfs(rt);
    printf("%lld\n",ans);
    return 0;
}

「FJ2014集訓 采藥人的路徑」