BZOJ2286: [Sdoi2011]消耗战

题解:

又是一个大坑。。。

算法一:很明显,最小割。预计得分20分。

算法二:每次做一遍树DP,预计得分40分。

算法三:虚树+单调栈。

算法三是为了优化算法二而出现的,因为关键点很少,而我们每次都要dfs整棵树过于浪费。

而我们只把关键点和它们的lca拎出来。使得每个点要不是关键点,要不是lca用来汇总答案。

因为其它点只是某条链上的中间点,完全没必要。

具体实现可以按dfs序排序,然后求lca,往栈里压,没用的就弹出。

这里说了一句话很好:lca的单调性。这保证了前面已经弹出的节点及lca不会再次出现。

代码:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<iostream>
  7 #include<vector>
  8 #include<map>
  9 #include<set>
 10 #include<queue>
 11 #include<string>
 12 #define inf 1000000000000LL
 13 #define maxn 250000+5
 14 #define maxm 100000+5
 15 #define eps 1e-10
 16 #define ll long long
 17 #define pa pair<int,int>
 18 #define for0(i,n) for(int i=0;i<=(n);i++)
 19 #define for1(i,n) for(int i=1;i<=(n);i++)
 20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
 22 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
 23 #define mod 1000000007
 24 using namespace std;
 25 inline int read()
 26 {
 27     int x=0,f=1;char ch=getchar();
 28     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 29     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
 30     return x*f;
 31 }
 32 int n,m,id[maxn],cnt,dep[maxn],f[maxn][19],g[maxn][19];
 33 ll dp[maxn];
 34 bool v[maxn];
 35 inline int lca(int x,int y)
 36 {
 37     if(dep[x]<dep[y])swap(x,y);
 38     int t=dep[x]-dep[y];
 39     for0(i,18)if(t&(1<<i))x=f[x][i];
 40     if(x==y)return x;
 41     for3(i,18,0)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
 42     return f[x][0];
 43 }
 44 inline int dist(int x,int y)
 45 {
 46     int t=dep[x]-dep[y],ret=1000000000;
 47     for3(i,18,0)if(t&(1<<i))ret=min(ret,g[x][i]),x=f[x][i];
 48     return ret;
 49 }
 50 struct graph
 51 {
 52     int head[maxn],tot;
 53     struct edge{int go,next,w;}e[2*maxn];
 54     inline void add(int x,int y,int w)
 55     {
 56         e[++tot]=(edge){y,head[x],w};head[x]=tot;
 57         e[++tot]=(edge){x,head[y],w};head[y]=tot;
 58     }
 59     inline void add(int x,int y)
 60     {
 61         e[++tot]=(edge){y,head[x],0};head[x]=tot;
 62     }
 63     inline void dfs(int x)
 64     {
 65         id[x]=++cnt;
 66         for1(i,20)if(dep[x]>=1<<i)f[x][i]=f[f[x][i-1]][i-1],g[x][i]=min(g[x][i-1],g[f[x][i-1]][i-1]);
 67         else break;
 68         for4(i,x)if(!dep[y])
 69         {
 70           dep[y]=dep[x]+1;f[y][0]=x;g[y][0]=e[i].w;
 71           dfs(y);
 72         }
 73     }
 74     inline void dfs(int x,int fa)
 75     {
 76         dp[x]=0;
 77         for4(i,x)if(y!=fa)
 78         {
 79             dfs(y,x);
 80             dp[x]+=min(v[y]?inf:dp[y],(ll)dist(y,x));
 81         }
 82         head[x]=0;
 83     }
 84 }G1,G2;    
 85 int a[maxn],sta[maxn],top;
 86 inline bool cmp(int x,int y){return id[x]<id[y];}    
 87 int main()
 88 {
 89     freopen("input.txt","r",stdin);
 90     freopen("output.txt","w",stdout);
 91     n=read();
 92     for1(i,n-1){int x=read(),y=read();G1.add(x,y,read());}
 93     dep[1]=1;
 94     G1.dfs(1);
 95     int T=read();
 96     while(T--)
 97     {
 98         m=read();
 99         for1(i,m)a[i]=read();
100         sort(a+1,a+m+1,cmp);
101         for1(i,m)v[a[i]]=1;
102         sta[top=1]=1;G2.tot=0;
103         for1(i,m)
104         {
105             int x=a[i],f=lca(x,sta[top]);
106             while(dep[f]<dep[sta[top]])
107             {
108               if(dep[f]>=dep[sta[top-1]])
109               {
110                  G2.add(f,sta[top--]);
111                    if(sta[top]!=f)sta[++top]=f;
112                    break;
113               }
114               G2.add(sta[top-1],sta[top]);top--;
115             }
116             if(sta[top]!=x)sta[++top]=x;
117         }
118         while(--top)G2.add(sta[top],sta[top+1]);
119         G2.dfs(1,0);
120         printf("%lld\n",dp[1]);
121         for1(i,m)v[a[i]]=0;
122     }        
123     return 0;
124 }
View Code

 

 

2286: [Sdoi2011]消耗战

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 520  Solved: 140
[Submit][Status]

Description

 

在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。

侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到1号岛屿上)。不过侦查部门还发现了这台机器只能够使用m次,所以我们只需要把每次任务完成即可。

 

Input

第一行一个整数n,代表岛屿数量。

接下来n-1行,每行三个整数u,v,w,代表u号岛屿和v号岛屿由一条代价为c的桥梁直接相连,保证1<=u,v<=n且1<=c<=100000。

第n+1行,一个整数m,代表敌方机器能使用的次数。

接下来m行,每行一个整数ki,代表第i次后,有ki个岛屿资源丰富,接下来k个整数h1,h2,…hk,表示资源丰富岛屿的编号。

 

Output

输出有m行,分别代表每次任务的最小代价。

posted @ 2015-01-17 22:56  ZYF-ZYF  Views(525)  Comments(2Edit  收藏  举报