zoukankan      html  css  js  c++  java
  • bzoj3677: [Apio2014]连珠线

    Description

    在列奥纳多·达·芬奇时期,有一个流行的童年游戏,叫做“连珠线”。不出所料,玩这个游戏只需要珠子和线,珠子从1到礼编号,线分为红色和蓝色。游戏 
    开始时,只有1个珠子,而接下来新的珠子只能通过线由以下两种方式被加入: 
    1.Append(w,杪):-个新的珠子w和一个已有的珠子杪连接,连接使用红线。 
    2.Insert(w,u,v):-个新的珠子w加入到一对通过红线连接的珠子(u,杪) 
    之间,并将红线改成蓝线。也就是将原来u连到1的红线变为u连到w的蓝线与W连到V的蓝线。 
    无论红线还是蓝线,每条线都有一个长度。而在游戏的最后,将得到游戏的 
    最后得分:所有蓝线的长度总和。 
    现在有一个这个游戏的最终结构:你将获取到所有珠子之间的连接情况和所 
    有连线的长度,但是你并不知道每条线的颜色是什么。 
    你现在需要找到这个结构下的最大得分,也就是说:你需要给每条线一个颜 
    色f红色或蓝色),使得这种连线的配色方案是可以通过上述提到的两种连线方式 
    操作得到的,并且游戏得分最大。在本题中你只需要输出最大的得分即可。 

    Input

     
    第一行是一个正整数n,表示珠子的个数,珠子编号为1刭n。 
    接下来n-l行,每行三个正整数ai,bi(l≤ai10000),表示有一条长度为ci的线连接了珠子ai和珠子bi。 

    Output

    输出一个整数,为游戏的最大得分。 

    Sample Input

    5
    1 2
    1 3 4 0
    1 4 1 5
    1 5 2 0

    Sample Output

    60



    HINT

    数据范围满足1≤n≤200000。 

    题解:

    假如确定了根,再通过若干操作得到这棵树,那么对于insert(w,u,v)操作,u,w,v必然为祖父节点-父节点-子节点的形式

    然后可以O(n)的枚举根,设 f[i][0/1] 表示以i为根的子树,i是否为中转点的情况下,子树蓝边的最大总和是多少

    这个可以O(1)的从儿子转移过来,所以dp的复杂度为O(n),但总复杂度为O(n2

    我们可以在状态里多加一个0/1,即设 f[i][0/1][0/1] 表示以i为根的子树,以i的为子树里除去i以外是否有根节点,i是否为中转点的情况下,子树蓝边的最大总和是多少

    当以i的为子树里除去i以外没有根节点,和前面的转移一样

    否则,就会多一种转移,设根节点在j,就是可以有insert(i,j,x),其中x是i的另一个子节点

    code:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<algorithm>
     6 using namespace std;
     7 char ch;
     8 bool ok;
     9 void read(int &x){
    10     for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
    11     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
    12     if (ok) x=-x;
    13 }
    14 const int maxn=200005;
    15 const int maxm=maxn*2;
    16 const int inf=2147483647;
    17 int n,a,b,c;
    18 int f[maxn][2][2];
    19 struct Graph{
    20     int tot,now[maxn],son[maxm],pre[maxm],val[maxm];
    21     int premax[maxn],sufmax[maxn],g[maxn];
    22     void put(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
    23     void add(int a,int b,int c){put(a,b,c),put(b,a,c);}
    24     void dfs(int u,int fa){
    25         for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) if (v!=fa) dfs(v,u);
    26         int cnt=0,sum=0; premax[0]=sufmax[0]=-inf;
    27         for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) if (v!=fa)
    28             g[v]=max(f[v][0][0],f[v][0][1]+val[p]),sum+=g[v],++cnt,premax[cnt]=sufmax[cnt]=f[v][0][0]+val[p]-g[v];
    29         premax[cnt+1]=sufmax[cnt+1]=-inf;
    30         for (int i=1;i<=cnt;i++) premax[i]=max(premax[i],premax[i-1]);
    31         for (int i=cnt;i>=1;i--) sufmax[i]=max(sufmax[i],sufmax[i+1]);
    32         f[u][0][0]=sum,f[u][0][1]=cnt?f[u][0][0]+premax[cnt]:-inf,f[u][1][1]=-inf;
    33         for (int p=now[u],v=son[p],i=0;p;p=pre[p],v=son[p]) if (v!=fa){i++;
    34             int res=max(premax[i-1],sufmax[i+1]),tmp=sum-g[v];
    35             f[u][1][0]=max(f[u][1][0],max(f[v][1][1]+val[p]+tmp,max(f[v][0][0],f[v][1][0])+tmp+max(val[p]+res,0)));
    36             f[u][1][1]=max(f[u][1][1],max(f[v][0][0],f[v][1][0])+val[p]+tmp);
    37         }
    38     }
    39 }G;
    40 int main(){
    41     read(n);
    42     for (int i=1;i<n;i++) read(a),read(b),read(c),G.add(a,b,c);
    43     G.dfs(1,0);
    44     printf("%d
    ",max(f[1][1][0],f[1][0][0]));
    45     return 0;
    46 }
  • 相关阅读:
    Node_JS
    读JS高级——第五章-引用类型 _记录
    读JS高级(兼容&&BOM&&私有变量&&面向对象)
    JS高级设计第七章——复习知识点
    nodeJs抓取网页
    表单脚本api_contenteditable
    泛——复习js高级第三版
    nodeJS
    Eclipse布局问题小记
    再议负载均衡算法
  • 原文地址:https://www.cnblogs.com/chenyushuo/p/5434054.html
Copyright © 2011-2022 走看看