题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用

分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用

对于父亲x,儿子y

①y为关键点:\(dp[x]\)+=\(dismn(x,y)\)

②y不为关键点:要么断y,要么断y所有子树

\(dp[x]\)+=\(min(dismn(x,y),dp[y])\)

=========================================================

关于兼容性的一种讨论

dismn(x,y)直接改为dismn(1,x)预处理算可以吗

当然不行?

交一发,A

兼容性:若要算到y,则y到1路径中没有关键点

①情况无影响

②情况中若子树中最小值算到了上面,断y定更优,而断y又变成父节点的①②情况讨论

所以是可以的咯

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
using namespace std;
typedef long long LL;
const int M=250007;
inline int rd(){
    int x=0;bool f=1;char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=0;
    for(;isdigit(c);c=getchar())x=x*10+c-48;
    return f?x:-x;
}

int n,m;

LL dp[M];
LL dis[M];
LL w[M][20];
int ln[M];

int dep[M],sz[M],son[M],pre[M];
int top[M],dfn[M],pid[M],T;

int que[M],kd[M];
bool cmp(int x,int y){return dfn[x]<dfn[y];}
int st[M],tot;

int g[M],te;
struct edge{int y,next;LL d;}e[M<<1];
void addedge(int x,int y,LL d){
    e[++te].y=y;e[te].d=d;e[te].next=g[x];g[x]=te;
}

int hd[M],td;
struct link{int y,next;}dw[M];
void addlink(int x,int y){
    if(x==y)return;
    dw[++td].y=y;dw[td].next=hd[x];hd[x]=td;
}

void dfs1(int x){
    sz[x]=1;
    int p,y;
    for(p=g[x];p;p=e[p].next)
    if((y=e[p].y)!=pre[x]){
        dep[y]=dep[x]+1;
        dis[y]=e[p].d;
        pre[y]=x;
        dfs1(y);
        sz[x]+=sz[y];
        if(sz[y]>sz[son[x]]) son[x]=y;
    }
}

void dfs2(int x){
    pid[dfn[x]=++T]=x;
    if(son[x]){
        top[son[x]]=top[x];
        dfs2(son[x]);
    }
    int p,y;
    for(p=g[x];p;p=e[p].next)
    if((y=e[p].y)!=pre[x]&&y!=son[x]){
        top[y]=y;
        dfs2(y);
    }
}

int LCA(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        x=pre[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    return x;
}

void vbuild(int z){
    int i,x,anc;
    sort(que+1,que+z+1,cmp);
    for(i=1;i<z;i++){
        anc=LCA(que[i],que[i+1]);
        hd[anc]=0; kd[anc]=2; dp[anc]=0;
    }
    hd[1]=0; dp[1]=0;//*****
    for(i=1;i<=z;i++){
        x=que[i];
        hd[x]=0; kd[x]=1; dp[x]=0;
    }
    td=0;
    tot=0;
    st[++tot]=1;
    for(i=1;i<=z;i++){
        x=que[i];
        anc=LCA(x,st[tot]);
        if(anc==st[tot]){
            st[++tot]=x;
            continue;
        }
        else{
            while( tot>1 && dep[anc]<=dep[st[tot-1]]){
                addlink(st[tot-1],st[tot]);
                tot--;
            }
            addlink(anc,st[tot]);
            st[tot]=anc;
            st[++tot]=x;
        }
    }
    for(i=1;i<tot;i++) addlink(st[i],st[i+1]);
}

LL getm(int x,int y){
    int l=ln[y-x+1];
    return min(w[x][l],w[y-(1<<l)+1][l]);
}

void init(){
    int i,j,l;
    for(i=2;i<=n;i++) ln[i]=ln[i>>1]+1;
    for(i=1;i<=n;i++) w[i][0]=dis[pid[i]];
    for(i=n;i>0;i--){
        l=ln[n-i+1];
        for(j=1;j<=l;j++) w[i][j]=min(w[i][j-1],w[i+(1<<j-1)][j-1]);
    }
}

LL getw(int x,int y){
    LL res=1LL<<61;
    while(dep[top[x]]>dep[y]){
        res=min(res,getm(dfn[top[x]],dfn[x]));
        x=pre[top[x]];
    }
    if(x!=y) res=min(res,getm(dfn[y]+1,dfn[x]));
    return res;
}

void dfs(int x){
    int p,y;
    LL tp;
    for(p=hd[x];p;p=dw[p].next){
        y=dw[p].y;
        tp=getw(y,x);
        if(kd[y]==1) dp[x]+=tp;
        else{
            dfs(y);
            dp[x]+=min(tp,dp[y]);
        }
    }
}

int main(){
    int i,x,y,z;
    n=rd();
    for(i=1;i<n;i++){
        x=rd(),y=rd(),z=rd();
        addedge(x,y,z);
        addedge(y,x,z);
    }

    dep[1]=pre[1]=0;
    dis[1]=0;
    dfs1(1);
    top[1]=1;
    dfs2(1);

    init();

    m=rd();
    while(m--){
        z=rd();
        for(i=1;i<=z;i++) que[i]=rd();
        vbuild(z);
        dfs(1);
        printf("%lld\n",dp[1]);
    }
    return 0;
}

bzoj 2286 [Sdoi2011]消耗战 虚树+dp的更多相关文章

  1. bzoj 2286: [Sdoi2011]消耗战 虚树+树dp

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一 ...

  2. 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP

    [题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...

  3. BZOJ 2286: [Sdoi2011]消耗战 虚树 树形dp 动态规划 dfs序

    https://www.lydsy.com/JudgeOnline/problem.php?id=2286 wa了两次因为lca犯了zz错误 这道题如果不多次询问的话就是裸dp. 一棵树上多次询问,且 ...

  4. BZOJ.2286.[SDOI2011]消耗战(虚树 树形DP)

    题目链接 BZOJ 洛谷P2495 树形DP,对于每棵子树要么逐个删除其中要删除的边,要么直接断连向父节点的边. 如果当前点需要删除,那么直接断不需要再管子树. 复杂度O(m*n). 对于两个要删除的 ...

  5. BZOJ 2286 [Sdoi2011]消耗战 ——虚树

    虚树第一题. 大概就是建一颗只与询问有关的更小的新树,然后在虚树上DP #include <map> #include <ctime> #include <cmath&g ...

  6. BZOJ 2286: [Sdoi2011]消耗战 虚树

    Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军 ...

  7. [BZOJ2286][SDOI2011]消耗战(虚树DP)

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4998  Solved: 1867[Submit][Statu ...

  8. BZOJ 2286: [Sdoi2011]消耗战

    2286: [Sdoi2011消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2082  Solved: 736[Submit][Status] ...

  9. BZOJ 3572 [HNOI2014]世界树 (虚树+DP)

    题面:BZOJ传送门 洛谷传送门 题目大意:略 细节贼多的虚树$DP$ 先考虑只有一次询问的情况 一个节点$x$可能被它子树内的一个到x距离最小的特殊点管辖,还可能被管辖fa[x]的特殊点管辖 跑两次 ...

随机推荐

  1. Android Studio没有导包快捷键怎么办

    Android Studio没有导包快捷键,那怎么办呢? 在使用Eclipse开发Android应用时,开发者往往会使用Shift+Ctrl+O快捷键来快速导入所有的包,和移除未使用的包.但这个快捷键 ...

  2. Mysql获取去重后的总数

    如果一张表中某个字段存在重复的值,现在我想去重后获取这个字段值的总数 先看这张表 这张表中的openid有重复值 怎么通过sql语句获取openid的去重总数呢 select count(distin ...

  3. 转 Fragment 和 FragmentActivity的使用

    今天学习下 Android中的 Fragment 和 FragmentActivity,因为没有4.0手机,平台是2.3.3 所以我是使用 v4 support 包来进行学习. 要想用Fragment ...

  4. IIS判断W3WP进程对应哪个网站

    IIS 6 (Win2003 )中查看某个应用程序池对应那个 W3WP.exe 进程,可以使用如下命令,输出结果类似如下: C:\WINDOWS\system32>cscript iisapp. ...

  5. 关于MyEclipse不停报错multiple problems have occurred 或者是内存不足 的解决办法

    这是因为 worksapace与svn代码不一样,要更新! 一更新就好了,困扰死我了,卧槽,搞了2个小时,难怪svn一提交就卡死人,原来还就是svn的问题,更新一下就行.

  6. 关于tomcat配置MyEclipse项目的配置代码

    例如:<Context path="/shis" docBase="E:\Genuitec\Workspaces\MyEclipse 8.6\zwfw_platfo ...

  7. ViewController 视图控制器

    [父视图控制器 addChildViewController:子视图控制器]; 在此,图控制器A添加了另一个图控制器B,那么A充当父视图控制器,B充当子视图控制器.父视图控制器充当了视图控制器容器的角 ...

  8. hrbustoj 1125 循环小数 II(小数变分数+极限思想)

    #include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #i ...

  9. 我的第一个Android项目之环境搭建

    开发IDE Android Studio2.0 + Genymotion + JDK1.8 网盘地址:http://pan.baidu.com/s/1kUSVqaN Android Studio 我的 ...

  10. USACO Section 1.2 Milking Cows 解题报告

    题目 题目描述 有3个农夫每天早上五点钟便起床去挤牛奶,现在第一个农夫挤牛奶的时刻为300(五点钟之后的第300个分钟开始),1000的时候结束.第二个农夫从700开始,1200结束.最后一个农夫从1 ...