zoukankan      html  css  js  c++  java
  • BZOJ NOI十连测 第一测 T2

     思路:看到这题,就感觉是一道很熟悉的题目:

    http://www.cnblogs.com/qzqzgfy/p/5535821.html

    只不过这题的K最多可以到N,而且边权不再只是1,考试的时候yy了一下做法:

    找k次直径,第一次把边取反,要是第二次再取到同样的边,那就把它变成0,毕竟每条边只经过2次嘛,YY的很好,实际上,交上去,5分TAT

    后来听以为神犇说不是取0,而是继续取反,每条边取一次就取反一次,woc..

    PS还有一点:一开始我是准备找出里面一点,然后bfs找最远和次远的点,然后把路径取反的,后面想想太SB了,毕竟这两个点是有可能有相交路径的。。

      1 #include<cstdio>
      2 #include<cmath>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #define ll long long
      7 int dis[200005],val[200005],mxdis,d[200005],p;
      8 int tot,go[200005],next[200005],first[200005],n,k,C,cnt=0,ans1,ans2,id[200005];
      9 int pre[200005],edge[200005],op[200005],S,T,vis[200005],c[200005];
     10 int read(){
     11        int t=0,f=1;char ch=getchar();
     12        while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     13        while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
     14        return t*f;
     15 }
     16 void insert(int x,int y,int z){
     17        tot++;
     18        go[tot]=y;
     19        next[tot]=first[x];
     20        first[x]=tot;
     21        val[tot]=z;
     22 }
     23 void add(int x,int y,int z){
     24        insert(x,y,z);op[tot]=tot+1;insert(y,x,z);op[tot]=tot-1;
     25 }
     26 void dfs1(int x,int fa){
     27         d[x]=0;ll mx1=0,mx2=0;
     28         for (int i=first[x];i;i=next[i]){
     29             int pur=go[i];
     30             if (pur==fa) continue;
     31             dfs1(pur,x);
     32             if (d[pur]+val[i]>mx1) mx2=mx1,mx1=d[pur]+val[i];
     33             else if (d[pur]+val[i]>mx2) mx2=d[pur]+val[i];
     34         }
     35         if (mxdis<mx1+mx2) mxdis=mx1+mx2,S=x;
     36 }
     37 void clear(int x){
     38         for (int i=x;i!=S;i=pre[i]){
     39                val[edge[i]]=-val[edge[i]];val[op[edge[i]]]=-val[op[edge[i]]];
     40         }
     41 }
     42 int bfs(int x){
     43        int h=1,t=1;
     44        ll  mx=0;int Id=x;
     45        for (int i=0;i<=n;i++) dis[i]=vis[i]=pre[i]=edge[i]=c[i]=0;
     46         c[1]=x;
     47         vis[x]=1;
     48        while (h<=t){
     49             int now=c[h++];
     50             for (int i=first[now];i;i=next[i]){
     51                 int pur=go[i];
     52                 if (vis[pur]) continue;
     53                 dis[pur]=dis[now]+val[i];
     54                 pre[pur]=now;
     55                 edge[pur]=i;
     56                 vis[pur]=1;
     57                 c[++t]=pur; 
     58             }
     59         }
     60         for (int i=1;i<=n;i++)
     61              if (mx<dis[i]) mx=dis[i],Id=i;
     62         return Id;
     63 }
     64 void clear(){
     65         T=bfs(S);
     66          ll sx=0;int Id=S;
     67          for (int i=1;i<=n;i++)
     68               if (i!=S&&i!=T&&sx<dis[i]) sx=dis[i],Id=i;
     69          clear(Id);clear(T);          
     70 }
     71 void Find_longest(){
     72         mxdis=-0x7fffffff;
     73         dfs1(1,0);
     74         clear();
     75 }
     76 void dfs(int x,int fa){
     77       int mx1=0,mx2=0;d[x]=0;int id1=x,id2=x;
     78       for (int i=first[x];i;i=next[i]){
     79          int pur=go[i];
     80          if (pur==fa) continue;
     81          dfs(pur,x);
     82          if (d[pur]+val[i]>mx1) mx2=mx1,mx1=d[pur]+val[i],id2=id1,id1=id[pur];
     83          else if (d[pur]+val[i]>mx2) mx2=d[pur]+val[i],id2=id[pur];
     84          }
     85      id[x]=id1;
     86      d[x]=mx1;
     87      if (mxdis<mx1+mx2) mxdis=mx1+mx2,ans1=id1,ans2=id2;
     88 }
     89 void dfss(int x,int y,int fa){
     90      if (!x||!y) return;
     91      if (x==y) {p=1;return;}
     92      for (int i=first[x];i;i=next[i]){
     93         int pur=go[i];
     94         if (pur==fa) continue;
     95         dfss(pur,y,x);
     96         if (p) {val[i]=-val[i],val[op[i]]=-val[op[i]];return;}  
     97         }
     98 }
     99 int main(){
    100       while (scanf("%d",&n)!=EOF){
    101          k=read();C=read();
    102           tot=0;
    103           int sum=0;
    104           for (int i=1;i<=n;i++) first[i]=0;
    105           for (int i=1;i<n;i++){
    106             int x=read(),y=read(),z=read();
    107             x++;y++;
    108             add(x,y,z);
    109             sum+=z; 
    110          }
    111          sum*=2;
    112          for (int i=1;i<=k;i++){
    113              mxdis=0;
    114             dfs(1,0);
    115              if (mxdis<C) break;
    116              sum=sum-mxdis+C;
    117              p=0;
    118              dfss(ans1,ans2,0);
    119           }
    120           printf("%d
    ",sum);
    121       }
    122 }

    然后听说有树形dp做法,由于每条边至多经过2次。假如每次穿越都新加了一条"穿越边",每次穿越都新加了2个"新点",假如子树x内有k个新点,那么(fa[x],x)这条边经过的边奇偶性和k个奇偶性相同,因为要从0出发,再回到0,这是个欧拉回路,因此进入子树p有x条边的话,离开子树p也必须是x条边,因此,奇偶性相同就得证了,由此我们设dp方程

    f[x][p]代表x的子树,有p个新节点的最小代价,然后用树上背包做就好了,(虽然这看起来像n^3,但是是n^2.....)

     1 #include<cstdio>
     2 #include<cmath>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 #define inf 0x3f3f3f3f
     7 int tot,go[200005],first[200005],next[200005],val[200005];
     8 int son[200005],f[2005][2005],g[2005],n,K,C;
     9 int read(){
    10     int t=0,f=1;char ch=getchar();
    11     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    12     while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
    13     return t*f;
    14 }
    15 void insert(int x,int y,int z){
    16     tot++;
    17     go[tot]=y;
    18     next[tot]=first[x];
    19     first[x]=tot;
    20     val[tot]=z;
    21 }
    22 void add(int x,int y,int z){
    23     insert(x,y,z);insert(y,x,z);
    24 }
    25 void dfs(int x,int fa,int y){
    26     son[x]=1;
    27     for (int i=1;i<=n;i++) f[x][i]=inf;
    28     f[x][0]=0;
    29     for (int i=first[x];i;i=next[i]){
    30         int pur=go[i];
    31         if (pur==fa) continue;
    32         dfs(pur,x,val[i]);
    33         for (int j=0;j<=son[x];j++) g[j]=f[x][j],f[x][j]=inf;
    34         for (int j=0;j<son[x];j++)
    35          for (int k=0;k<=son[pur];k++)
    36           f[x][j+k]=std::min(f[x][j+k],g[j]+f[pur][k]); 
    37         son[x]+=son[pur];  
    38     }
    39     for (int i=son[x];i>=1;i--)
    40      f[x][i]=std::min(f[x][i],f[x][i-1]);
    41     for (int i=0;i<=son[x];i++) f[x][i]+=((i%2==0)+1)*y; 
    42 }
    43 int main(){
    44     while (scanf("%d",&n)!=EOF){
    45         K=read();C=read();
    46         tot=0;
    47         for (int i=1;i<=n;i++)
    48          first[i]=0;
    49         for (int i=1;i<n;i++){
    50             int x=read(),y=read(),z=read();
    51             x++;y++;
    52             add(x,y,z);
    53         }
    54         dfs(1,0,0);
    55         int ans=inf;
    56         for (int i=0;i<=K&&i*2<=n;i++)
    57          ans=std::min(ans,f[1][i*2]+C*i);
    58         printf("%d
    ",ans); 
    59     }
    60 }
  • 相关阅读:
    360手机青春版原装充电器
    然并卵却很拉风!360超级充电器评测_天极网
    39元超值!360超级充电器拆解与评测
    99元紫米10000mAh移动电源开箱拆解
    自己DIY PCB电路板制作(简单方便快捷)
    Easy EDA:在线创客软件服务是未来的趋势 | 雷锋网
    EasyEDA
    我的那些年(9)~我来团队了,Mvc兴起了
    我的那些年(8)~去朋友公司做网站开发
    我的那些年(7)~第一份互联网工作
  • 原文地址:https://www.cnblogs.com/qzqzgfy/p/5588335.html
Copyright © 2011-2022 走看看