zoukankan      html  css  js  c++  java
  • BZOJ2286 [Sdoi2011]消耗战

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

     

     

    Sample Input

    10
    1 5 13
    1 9 6
    2 1 19
    2 4 8
    2 3 91
    5 6 8
    7 5 4
    7 8 31
    10 7 9
    3
    2 10 6
    4 5 7 8 3
    3 9 4 6

    Sample Output

    12
    32
    22

    HINT

     对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1

     

    正解:虚树+树形DP

    解题报告:

      听说这是虚树裸题,于是我跑过来AC了。

      考虑直接树形DP,点数过多,而且大多数没有用,会超时。那我们想保留一些必要的点,而去掉无用的点。

      首先虚树的构建也是一个很神的算法。网上代码很多,但是总结还是少。

       遥遥的题解,传送门:http://user.qzone.qq.com/872191552/blog/1464431226

      考虑维护一个栈,每次往里面插新结点,然后特判一下二者的lca和栈顶元素的情况。具体的看遥遥的吧,懒得说了,等切世界树的时候再写一份详细的吧。

       

      UPD:

      昨天太懒了。现在还是仔细说一遍吧。

      具体做法挺简单,就是要想清楚才行。首先把询问点根据原树DFS序排序,显然这些点都要出现在虚树中来,而且为了保证结构不被破坏,另外一些跟他们有关系的点都要加入到虚树中来。我们用一个栈,维护原树上的一条链,自栈底到栈顶,深度由小变大。每次考虑插入询问点进栈。如果插入点的祖先是栈顶元素,那么直接插入即可,因为反正是一条链上的结点。如果不是的话,那么只有可能分居他们的lca的两棵子树中。现在我们就需要分类讨论,如果栈顶元素的下一位的深度比lca深,那么我们需要不断弹出栈顶元素,并且在弹出之前与栈顶下一位连一下边。直到lca深度比栈顶元素深,此时把lca加入栈,把需要插入的点加入栈,继续往下处理。又因为我们是按DFS序做的,这样就可以保证我们开始说的,维护的是树上的一条链。之后再DP就可以了。

     

      1 //It is made by jump~
      2 #include <iostream>
      3 #include <cstdlib>
      4 #include <cstring>
      5 #include <cstdio>
      6 #include <cmath>
      7 #include <algorithm>
      8 #include <ctime>
      9 #include <vector>
     10 #include <queue>
     11 #include <map>
     12 #include <set>
     13 #ifdef WIN32   
     14 #define OT "%I64d"
     15 #else
     16 #define OT "%lld"
     17 #endif
     18 using namespace std;
     19 typedef long long LL;
     20 const int MAXN = 250011;
     21 LL inf;//inf不能开小了
     22 int n,m,ecnt,tot,id[MAXN],k;
     23 int first[MAXN],next[MAXN*2],to[MAXN*2],w[MAXN*2];
     24 LL val[MAXN];//这个点到根上的最小边权
     25 int jump[MAXN][19],deep[MAXN];
     26 int que[MAXN],top,Stack[MAXN];
     27 int head[MAXN];
     28 LL f[MAXN];
     29 
     30 inline int getint()
     31 {
     32        int w=0,q=0;
     33        char c=getchar();
     34        while((c<'0' || c>'9') && c!='-') c=getchar();
     35        if (c=='-')  q=1, c=getchar();
     36        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
     37        return q ? -w : w;
     38 }
     39 
     40 struct edge{
     41     int to,next;
     42 }e[MAXN];
     43 
     44 inline LL min(LL x,LL y){ if(x<y) return x;  return y; }
     45 
     46 inline void dfs(int x,int fa){
     47     jump[x][0]=fa; id[x]=++ecnt;//作出dfs序
     48     for(int i=1;i<=18;i++) jump[x][i]=jump[jump[x][i-1]][i-1];
     49     for(int i=first[x];i;i=next[i]) {
     50     int v=to[i];
     51     if(v==fa) continue;
     52     val[v]=min(w[i],val[x]); deep[v]=deep[x]+1;
     53     dfs(v,x);
     54     }
     55 }
     56 
     57 inline bool cmp(int a,int b){return id[a]<id[b];}
     58 
     59 inline int lca(int x,int y){
     60     if(deep[x]<deep[y]) swap(x,y);
     61     int t=0; while((1<<t) <= deep[x]) t++;
     62     t--; for(int i=t;i>=0;i--) if(deep[x]-(1<<i)>=deep[y]) x=jump[x][i];
     63     if(x==y) return y;
     64     for(int i=t;i>=0;i--) if(jump[x][i]!=jump[y][i]) { x=jump[x][i]; y=jump[y][i]; } 
     65     return jump[x][0];
     66 }
     67 
     68 inline void link(int x,int y){ if(x==y) return ; e[++ecnt].next=head[x]; head[x]=ecnt; e[ecnt].to=y;}
     69 
     70 inline void dp(int x){
     71     LL lin=0; f[x]=val[x];
     72     for(int i=head[x];i;i=e[i].next) {
     73     dp(e[i].to);
     74     lin+=f[e[i].to];
     75     }
     76     head[x]=0;//退出的时候顺便清空
     77     if(!lin) f[x]=val[x];
     78     else if(lin<f[x]) f[x]=lin;
     79 }
     80 
     81 inline void solve(){//断绝到根结点1的路径
     82     m=getint(); for(int i=1;i<=m;i++) que[i]=getint();
     83     sort(que+1,que+m+1,cmp);//按dfs序排序
     84     tot=0; que[++tot]=que[1]; 
     85     for(int i=2;i<=m;i++) if(lca(que[i],que[tot])!=que[tot]) que[++tot]=que[i];//应该是和tot比较
     86     //在下面的肯定不用计算,只要切断上部的即可
     87     top=0;Stack[++top]=1; int grand;//最近公共祖先
     88     ecnt=0;
     89     for(int i=1;i<=tot;i++) {//分类讨论
     90     grand=lca(Stack[top],que[i]);
     91     while(1) {
     92         if(deep[Stack[top-1]]<=deep[grand]) {//分别处在两个子树,grand深度更大!!!
     93         link(grand,Stack[top]); top--;
     94         if(Stack[top]!=grand) Stack[++top]=grand;
     95         break;
     96         }
     97         link(Stack[top-1],Stack[top]); top--;
     98     }
     99     if(Stack[top]!=que[i]) Stack[++top]=que[i];//在同一子树
    100     }
    101     top--;
    102     while(top) link(Stack[top],Stack[top+1]),top--;//剩余的记得连上
    103     dp(1);
    104     printf(OT"
    ",f[1]);
    105 }
    106 
    107 inline void work(){
    108     n=getint(); int x,y,z;
    109     inf=1;for(int i=1;i<=60;i++) inf*=2;
    110     for(int i=1;i<n;i++) {
    111     x=getint(); y=getint(); z=getint();
    112     next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; w[ecnt]=z;
    113     next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x; w[ecnt]=z;
    114     }
    115     val[1]=inf; ecnt=0; deep[1]=0; dfs(1,0);
    116     k=getint(); for(int i=1;i<=k;i++) solve();
    117 }
    118 
    119 int main()
    120 {
    121   work();
    122   return 0;
    123 }
  • 相关阅读:
    滚动页面时DIV到达顶部时固定在顶部
    【Java学习笔记】拾遗
    【Java学习笔记】文件信息
    【Java学习笔记】使用BufferedReader类(流的读写)
    【Java学习笔记】可变参数
    【Java学习笔记】控制台读写
    【Java学习笔记】关于默认值
    【Java学习笔记】FileChannel的学习
    【JAVA学习笔记】静态导入
    【Java学习笔记】Java中关于tostring方法的误操作
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5701801.html
Copyright © 2011-2022 走看看