zoukankan      html  css  js  c++  java
  • [BZOJ 3697]采药人的路径(点分治)

    Description

    采药人的药田是一个树状结构,每条路径上都种植着同种药材。
    采药人以自己对药材独到的见解,对每种药材进行了分类。大致分为两类,一种是阴性的,一种是阳性的。
    采药人每天都要进行采药活动。他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径。采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的。他想知道他一共可以选择多少种不同的路径。

    Solution

    一开始是按只有重心才作为休息站写的,写着写着发现并不是这样…后来看了黄学长的代码

    好鬼畜的点分治QwQ

    先把边权为0的变为-1,这样和为0就意味着阴阳平衡

    h[i][1/0]表示之前的子树距离为i,是否存在休息站的路径的数量,g[i][1/0]表示这一子树距离为i,是否存在休息站的路径的数量

    存在休息站与否可以用同一距离是否第二次出现来判定(这说明这一段的和一定是0)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #define INF 0x3f3f3f3f
    #define MAXN 100005
    typedef long long LL;
    using namespace std;
    int n,root=0,tot=0,num,maxdeep,t[2*MAXN],siz[MAXN],maxv[MAXN],head[MAXN],cnt=0;
    LL ans=0,g[MAXN*2][2],h[MAXN*2][2];
    bool vis[MAXN];
    struct Node1
    {
        int next,to,w;
    }Edges[MAXN*2];
    int read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    void addedge(int u,int v,int w)
    {
        Edges[++cnt].next=head[u];
        head[u]=cnt;
        Edges[cnt].to=v,Edges[cnt].w=w;
    }
    void getroot(int u,int f)
    {
        siz[u]=1,maxv[u]=0;
        for(int i=head[u];~i;i=Edges[i].next)
        {
            int v=Edges[i].to;
            if(v==f||vis[v])continue;
            getroot(v,u);
            siz[u]+=siz[v],maxv[u]=max(maxv[u],siz[v]);
        }
        maxv[u]=max(maxv[u],tot-siz[u]);
        if(maxv[u]<maxv[root])root=u;
    }
    void getdeep(int u,int f,int d)
    {
        maxdeep=max(maxdeep,abs(d-n));
        if(t[d])g[d][1]++;
        else g[d][0]++;
        t[d]++;
        for(int i=head[u];~i;i=Edges[i].next)
        {
            int v=Edges[i].to;
            if(v==f||vis[v])continue;
            getdeep(v,u,d+Edges[i].w);
        }
        t[d]--;
    }
    void work(int u)
    {
        int mx=0;
        vis[u]=1,h[n][0]=1;
        for(int i=head[u];~i;i=Edges[i].next)
        {
            int v=Edges[i].to;
            if(vis[v])continue;
            maxdeep=1;
            getdeep(v,0,n+Edges[i].w);
            mx=max(mx,maxdeep);
            ans+=(h[n][0]-1)*g[n][0];
            for(int j=-maxdeep;j<=maxdeep;j++)
            ans+=h[n-j][1]*g[n+j][1]+h[n-j][0]*g[n+j][1]+h[n-j][1]*g[n+j][0];
            for(int j=n-maxdeep;j<=n+maxdeep;j++)
            {
                h[j][1]+=g[j][1];
                h[j][0]+=g[j][0]; 
                g[j][1]=g[j][0]=0;
            }
        }
        for(int i=n-mx;i<=n+mx;i++)h[i][0]=h[i][1]=0;
        for(int i=head[u];~i;i=Edges[i].next)
        {
            int v=Edges[i].to;
            if(vis[v])continue;
            root=0,tot=siz[v];
            getroot(v,u),work(root);
        }
    }
    int main()
    {
        memset(head,-1,sizeof(head));
        n=read();
        for(int i=1;i<n;i++)
        {
            int a=read(),b=read(),t=read();
            if(!t)t=-1;
            addedge(a,b,t),addedge(b,a,t);
        }
        maxv[0]=INF,tot=n;
        getroot(1,0),work(root);
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    使用dataInput:DescriptionViewer对输入的数据进行校验
    Nunit2.6.2调试.net4类库
    使用WCF RIA服务支持ASP.NET验证
    偶遇 Lc.exe已退出代码为1
    android程序连接后端web service时,提示:Permission denied
    设置XP系统的自动登录
    DomainDataSource的自动刷新
    安装CentOS时,显示 NET:Registered protocol family 2
    清除SqlServer2008的日志
    http://www.cnblogs.com/KnightsWarrior/archive/2010/08/27/1809739.html(博客主)
  • 原文地址:https://www.cnblogs.com/Zars19/p/6941480.html
Copyright © 2011-2022 走看看