1. 程式人生 > >Luogu-2495 [SDOI2011]消耗戰

Luogu-2495 [SDOI2011]消耗戰

ring ear wap \n can void names algorithm 其他

虛樹第一題

對於每次詢問的點建立一棵虛樹,然後在樹上DP,一個點的答案就是這個點的父邊切斷的代價與所有兒子切斷的代價去最小值,當然如果這個節點是資源點則必須切父邊

註意在虛樹上一條邊的代價應該是中間所有邊代價的最小值,在這道題裏可以用到根節點邊的最小值

建虛樹的時候可以不去建那些在其他資源點下面的資源點,他們不會對答案造成影響,並且這樣的話資源點都是葉節點,就不用給資源點打標記了23333

註意1點不能斷,特判一下就好了。

#include<map>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=3e5+100,maxm=5e5+100;
struct node{
    int fa,dep,top,son,siz;
}tre[maxn];
int head[maxn],nex[maxm],v[maxm],w[maxm],num=1,fee[maxn];
int n,t,tim,m,p[maxn],dfn[maxn],top,st[maxn],a,b,c;
vector<int>e[maxn];
void dfs1(int x,int fa,int dep){
    tre[x].dep=dep;
    tre[x].fa=fa;
    tre[x].siz=1;
    dfn[x]=++tim;
    for(int i=head[x];i;i=nex[i])
        if(v[i]!=fa){
            fee[v[i]]=min(fee[x],w[i]);
            dfs1(v[i],x,dep+1);
            if(tre[v[i]].siz>tre[tre[x].son].siz)
                tre[x].son=v[i];
            tre[x].siz+=tre[v[i]].siz;
        }
}
void dfs2(int x,int fa,int top){
    tre[x].top=top;
    if(tre[x].son) dfs2(tre[x].son,x,top);
    for(int i=head[x];i;i=nex[i])
        if(v[i]!=fa&&v[i]!=tre[x].son)
            dfs2(v[i],x,v[i]);
}
int Lca(int x,int y){
    int fx=tre[x].top,fy=tre[y].top;
    while(fx!=fy){
        if(tre[fx].dep<tre[fy].dep) swap(x,y),swap(fx,fy);
        x=tre[fx].fa;
        fx=tre[x].top;
    }
    return tre[x].dep>tre[y].dep?y:x;
}
void add(int x,int y,int z){
    v[++num]=y;
    w[num]=z;
    nex[num]=head[x];
    head[x]=num;
    v[++num]=x;
    w[num]=z;
    nex[num]=head[y];
    head[y]=num;
}
bool cmp(int x,int y){
    return dfn[x]<dfn[y];
}
void insert(int x){
    if(top==1){
        st[++top]=x;
        return;
    }
    int lca=Lca(st[top],x);
    if(lca==st[top]) return; //DP方便 
    while(top>1&&dfn[st[top-1]]>=dfn[lca])
        e[st[top-1]].push_back(st[top]),top--;
    if(lca!=st[top]) e[lca].push_back(st[top]),st[top]=lca;
    st[++top]=x;
}
ll dp(int x){
    if(e[x].size()==0) return 1ll*fee[x];
    ll tot=0;
    for(int i=0;i<e[x].size();i++)
        tot+=dp(e[x][i]);
    e[x].clear();
    if(x==1) return tot;
    else return min(tot,1ll*fee[x]);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<n;i++)
        scanf("%d%d%d",&a,&b,&c),add(a,b,c);
    dfs1(1,1,1);
    dfs2(1,1,1);
    scanf("%d",&t);
    while(t--){
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
            scanf("%d",&p[i]);
        sort(p+1,p+m+1,cmp);
        st[top=1]=1;
        for(int i=1;i<=m;i++) insert(p[i]);
        while(top>1) e[st[top-1]].push_back(st[top]),top--;
        printf("%lld\n",dp(1));
    }
    return 0;
}






Luogu-2495 [SDOI2011]消耗戰