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 }
原文地址:https://www.cnblogs.com/qzqzgfy/p/5588335.html