BZOJ2286: [Sdoi2011]消耗战

题解:首先构造虚数 然后树DP即可

/**************************************************************
    Problem: 2286
    User: c20161007
    Language: C++
    Result: Accepted
    Time:10752 ms
    Memory:94812 kb
****************************************************************/
 
#include <bits/stdc++.h>
const int MAXN=3e5+10;
#define ll long long
#define pii pair<int,int>
using namespace std;
const int inf=1e9+10;
vector<pii>vec[MAXN];
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
int n;
int f[MAXN][21];ll minn[MAXN][21];
int dep[MAXN],cnt,p[MAXN];
int st[MAXN];int tot;
vector<int>vv;
ll ans[MAXN];bool vis[MAXN];
void dfs(int v,int pre,int deep){
    dep[v]=deep+1;p[v]=++cnt;f[v][0]=pre;
    for(int i=0;i<vec[v].size();i++){
    int u=vec[v][i].first;
    if(u!=pre){
        minn[u][0]=vec[v][i].second;
        dfs(u,v,deep+1);
    }
    }
}
void dfs1(int v){
    for(int i=1;i<=20;i++)f[v][i]=f[f[v][i-1]][i-1],minn[v][i]=min(minn[v][i-1],minn[f[v][i-1]][i-1]);
    for(int i=0;i<vec[v].size();i++){
    if(vec[v][i].first!=f[v][0])dfs1(vec[v][i].first);
    }
}
int Lca(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    int tmp=dep[u]-dep[v];
    for(int i=0;i<=20;i++)if(tmp&(1<<i)){u=f[u][i];}
    if(u==v){return u;}
    for(int i=20;i>=0;i--){
    if(f[u][i]!=f[v][i]){
        v=f[v][i];u=f[u][i];
    }
    }
    return f[v][0];
}
void built(int x){
    vv.push_back(x);
    if(!tot){st[++tot]=x;return ;}
    int lca=Lca(x,st[tot]);
//    cout<<x<<"====="<<st[tot]<<" "<<lca<<endl;
    while(tot>1&&dep[lca]<dep[st[tot-1]]){
    vec[st[tot-1]].push_back(make_pair(st[tot],0));
    vec[st[tot]].push_back(make_pair(st[tot-1],0));
    tot--;
    }
    if(dep[lca]<dep[st[tot]]){
    vv.push_back(lca);
    vec[st[tot]].push_back(make_pair(lca,0));
    vec[lca].push_back(make_pair(st[tot],0));
    tot--;
    //  st[++tot]=lca;
    }
    if(!tot||dep[lca]>dep[st[tot]])st[++tot]=lca;
    st[++tot]=x;
}
ll dist(int u,int v){
    if(v==0)return inf;
    ll res=inf;
    for(int i=20;i>=0;i--){
    if(dep[f[u][i]]>dep[v]){
        res=min(res,minn[u][i]);
        u=f[u][i];
    }
    }
    res=min(res,minn[u][0]);
    return res;
}
void slove(int v,int pre){
   // cout<<v<<" "<<pre<<endl;
    for(int i=0;i<vec[v].size();i++){
    int u=vec[v][i].first;
    if(u!=pre){
        slove(u,v);
        if(vis[u])ans[v]+=dist(u,v);
        else ans[v]+=min(dist(u,v),ans[u]);
    }
    }
   // cout<<v<<" "<<ans[v]<<" ::::"<<endl;
}
bool cmp(int aa,int bb){return p[aa]<p[bb];}
vector<int>V;
int main(){
    n=read();int u,v,vul;
    for(int i=1;i<n;i++)u=read(),v=read(),vul=read(),vec[u].push_back(make_pair(v,vul)),vec[v].push_back(make_pair(u,vul));
    int q;q=read();int k,last;dfs(1,0,0);dfs1(1);
    for(int i=1;i<=n;i++)vec[i].clear();
    for(int i=1;i<=q;i++){
    k=read();tot=0;
//  V.push_back(1);
    for(int j=1;j<=k;j++)u=read(),V.push_back(u),vis[u]=1;
    sort(V.begin(),V.end(),cmp);
    for(int j=0;j<V.size();j++)built(V[j]);
    while(tot>1){vec[st[tot]].push_back(make_pair(st[tot-1],0)),vec[st[tot-1]].push_back(make_pair(st[tot],0));tot--;}
    //vv.push_back()
    if(st[1]!=1){vec[1].push_back(make_pair(st[1],0));vec[st[1]].push_back(make_pair(1,0));}
//  else last=1;
//  cout<<last<<endl;
    slove(1,0);
    printf("%lld\n",ans[1]);
    if(st[1]!=1)vec[1].clear(),ans[1]=0;
    for(int j=0;j<vv.size();j++)vec[vv[j]].clear(),ans[vv[j]]=0,vis[vv[j]]=0;
    V.clear();vv.clear();
    } 
    return 0;
}

 

2286: [Sdoi2011]消耗战

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 5381  Solved: 2041
[Submit][Status][Discuss]

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

posted @ 2018-08-05 17:57  wang9897  阅读(115)  评论(0编辑  收藏  举报