【bzoj2152】聪聪可可 点分治

    点分治求路径长度为3的倍数的链的条数,结果用分数表示。

    这道题明显是树形dp简单,然而还是写了点分治(练习所用没办法啊)。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 50005
using namespace std;
 
int n,m,tot,sum,rt,ans,t[3],fst[N],pnt[N],len[N],nxt[N],d[N],sz[N],f[N];
bool vis[N];
int read(){
    int x=0; char ch=getchar();
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
    return x;
}
void add(int aa,int bb,int cc){
    pnt[++tot]=bb; nxt[tot]=fst[aa]; len[tot]=cc; fst[aa]=tot;
}
void dfs(int x,int fa){
    sz[x]=f[x]=1; int p;
    for (p=fst[x]; p; p=nxt[p]){
        int v=pnt[p]; if (v==fa || vis[v]) continue;
        dfs(v,x); sz[x]+=sz[v];
        f[x]=max(f[x],sz[v]);
    }
    f[x]=max(f[x],sum-sz[x]); if (f[x]<f[rt]) rt=x;
}
void getdep(int x,int fa){
    t[d[x]]++; int p;
    for (p=fst[x]; p; p=nxt[p]){
        int v=pnt[p]; if (v==fa || vis[v]) continue;
        d[v]=(d[x]+len[p])%3; getdep(v,x);
    }
}
int work(int x,int num){
    d[x]=num; memset(t,0,sizeof(t));
    getdep(x,0); return t[0]*t[0]+t[1]*t[2]*2;
}
void solve(int x){
    ans+=work(x,0); vis[x]=1; int p;
    for (p=fst[x]; p; p=nxt[p]){
        int v=pnt[p]; if (vis[v]) continue;
        ans-=work(v,len[p]);
        sum=sz[v]; rt=0; dfs(v,x); solve(rt);
    }
}
int gcd(int x,int y){ return (y)?gcd(y,x%y):x; }
void print_ans(int x,int y){
    int tmp=gcd(x,y); printf("%d/%d\n",x/tmp,y/tmp);
}
int main(){
    n=read(); int i;
    for (i=1; i<n; i++){
        int x=read(),y=read(),z=read()%3;
        add(x,y,z); add(y,x,z);
    }
    f[rt=0]=sum=n; dfs(1,0);
    solve(rt); print_ans(ans,n*n);
    return 0;
}


2015.11.15

by lych

你可能感兴趣的:(DFS,点分治)