• 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
    ",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行,分别代表每次任务的最小代价。

  • 相关阅读:
    1.python全栈之路:python基础
    21、指定元素置后——数组
    20、泰勒展开式
    19、显示表达式的运算形式
    1、模拟蚂蚁借呗—利息计算
    05、C语言——循环结构
    04、C语言——选择结构
    03、C语言——顺序结构
    02、C语言——C语言组成与数据
    07、C语言——函数
  • 原文地址:https://www.cnblogs.com/zyfzyf/p/4231255.html
Copyright © 2020-2023  润新知