zoukankan      html  css  js  c++  java
  • bzoj千题计划248:bzoj3697: 采药人的路径

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

    点分治

    路径0改为路径-1

    g[i][0/1] 和 f[i][0/1]分别表示当前子树 和 已经处理完的兄弟节点子树 中,路径前缀和为i,前面是否还有一个前缀和为i的点

    合法的路径分为三类:

    1、路径以当前分治重心为端点,ans+=g[0][1]

    2、路径跨越分治重心,休息站在分治重心,ans+=g[0][0]*f[0][0]

    3、路径跨越分治重心,休息站不在分治重心,ans+= Σ g[i][0]*f[-i][1] + g[i][1]*f[-i][0] + g[i][1]*f[-i][1]  i∈[min_dis,max_dis]

    #include<cstdio>
    #include<iostream>
    
    #define N 100001
    
    using namespace std;
    
    typedef long long LL;
     
    int n;
    int tot,front[N],to[N<<1],nxt[N<<1],val[N<<1];
    
    int root,min_size;
    int siz[N],mx[N];
    
    bool vis[N];
    
    LL g[N<<1][2],f[N<<1][2];
    int cnt[N<<1];
    int max_dis,min_dis;
    
    LL ans;
    
    void read(int &x)
    {
         x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    void add(int u,int v,int w)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=w;
    }
    
    void get_size(int x,int fa)
    {
        siz[x]=1; mx[x]=0;
        for(int i=front[x];i;i=nxt[i])
            if(!vis[to[i]] && to[i]!=fa)
            {
                get_size(to[i],x);
                siz[x]+=siz[to[i]]; 
                if(siz[to[i]]>mx[x]) mx[x]=siz[to[i]];
            }
    }
    
    void get_root(int x,int pa,int fa)
    {
        mx[x]=max(mx[x],siz[pa]-siz[x]);
        if(mx[x]<min_size) min_size=mx[x],root=x;
        for(int i=front[x];i;i=nxt[i])
            if(to[i]!=fa && !vis[to[i]]) get_root(to[i],pa,x);
    }  
    
    void get_sum(int x,int fa,int d)
    {
        if(d>max_dis) max_dis=d; 
        if(d<min_dis) min_dis=d;
        cnt[d+n]++;
        if(cnt[d+n]==1) g[d+n][0]++;
        else g[d+n][1]++;
        for(int i=front[x];i;i=nxt[i])
            if(!vis[to[i]] && to[i]!=fa) get_sum(to[i],x,d+val[i]);
        cnt[d+n]--;
    }    
    
    void work(int x,int pa)
    {
        min_size=n+1;
        get_size(x,0);
        get_root(x,x,0);
        int maxn=-n,minn=n;
        for(int i=front[root];i;i=nxt[i])
            if(!vis[to[i]])
            {     
                max_dis=-n; 
                min_dis=n;
                get_sum(to[i],root,val[i]); 
                if(max_dis>maxn) maxn=max_dis;
                if(min_dis<minn) minn=min_dis;
                ans+=g[n][1];
                ans+=g[n][0]*f[n][0];
                for(int j=min_dis;j<=max_dis;++j) 
                    ans+=g[j+n][0]*f[-j+n][1]+g[j+n][1]*f[-j+n][0]+g[j+n][1]*f[-j+n][1];
                for(int j=min_dis;j<=max_dis;++j)
                {
                    f[j+n][0]+=g[j+n][0];
                    f[j+n][1]+=g[j+n][1];
                    g[j+n][0]=g[j+n][1]=0;
                }
            }
        for(int i=minn;i<=maxn;++i) f[i+n][0]=f[i+n][1]=0;
        vis[root]=true; 
        int rt=root;
        for(int i=front[root];i;i=nxt[i])
            if(!vis[to[i]]) work(to[i],rt);
    }
    
    int main()
    {
    //    freopen("data.in","r",stdin);
    //    freopen("my.out","w",stdout); 
        read(n);
        int u,v,w;
        for(int i=1;i<n;++i)
        {
            read(u); read(v); read(w);
            if(!w) w=-1;
            add(u,v,w);
        }
        work(1,0);
        cout<<ans;
    }

    3697: 采药人的路径

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1505  Solved: 515
    [Submit][Status][Discuss]

    Description

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

    Input

    第1行包含一个整数N。
    接下来N-1行,每行包含三个整数a_i、b_i和t_i,表示这条路上药材的类型。

    Output

    输出符合采药人要求的路径数目。

    Sample Input

    7
    1 2 0
    3 1 1
    2 4 0
    5 2 0
    6 3 1
    5 7 1

    Sample Output

    1

    HINT

    对于100%的数据,N ≤ 100,000。

  • 相关阅读:
    后可视化编程
    查看图片前进后退效果图
    [置顶] 后可视化编程
    xCAT安装配置文档
    jQuery邮箱验证
    2011级csdnjava张侃—Spring(1)
    [置顶] 后可视化编程时代
    php中Session使用方法详解
    关于浏览器ip代理导致定位错乱问题的坑
    PHPStorm使用技巧及快捷键
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8470627.html
Copyright © 2011-2022 走看看