【Luogu】P2495消耗战(虚树DP)

  题目链接

  我虚树没很理解啊qwq

  就是我们有比较少的询问点,然后我们把不需要考虑的点搞一搞扔掉,然后每次询问给那些询问点单独建一颗树,然后乱搞。

  ……好吧看来是完全没理解……

  链接大法qwq

  

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cctype>
#define maxn 500000
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

struct Edge{
    int next,to,val;
}edge[maxn*2];
int head[maxn],num;
inline void add(int from,int to,int val){
    edge[++num]=(Edge){head[from],to,val};
    head[from]=num;
}

int stack[maxn],top;
int deep[maxn];
int s[maxn][22];
int dfn[maxn],ID;
int q[maxn];
long long f[maxn];
long long ans[maxn];
bool flag[maxn];

void dfs(int x,int fa){
    deep[x]=deep[fa]+1;    dfn[x]=++ID;
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==fa)    continue;
        s[to][0]=x;
        f[to]=min(f[x],(long long)edge[i].val);
        dfs(to,x);
    }
    return;
}

bool cmp(int a,int b){    return dfn[a]<dfn[b];    }

int calclca(int a,int b){
    if(deep[a]<deep[b])    swap(a,b);
    int f=deep[a]-deep[b];
    for(int i=0;1<<i<=f;++i)
        if(f&(1<<i))    a=s[a][i];
    if(a==b)    return a;
    for(int i=20;i>=0;--i){
        if(s[a][i]==s[b][i])    continue;
        a=s[a][i];b=s[b][i];
    }
    return s[a][0];
}

void calc(int x,int fa){
    long long sum=0;
    ans[x]=f[x];
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==fa)    continue;
        calc(to,x);
        sum+=ans[to];
    }
    if(sum&&!flag[x])    ans[x]=min(ans[x],sum);
    head[x]=0;
    return;
}

int main(){
    f[1]=1e9;    f[1]=f[1]*f[1];
    int n=read();
    for(int i=1;i<n;++i){
        int from=read(),to=read(),val=read();
        add(from,to,val);
        add(to,from,val);
    }
    dfs(1,1);
    for(int i=1;i<=20;++i)
        for(int j=1;j<=n;++j)
            s[j][i]=s[s[j][i-1]][i-1];
    int m=read();
    memset(head,0,sizeof(head));
    for(int i=1;i<=m;++i){
        num=0;top=0;
        int x=read();    
        for(int j=1;j<=x;++j){    q[j]=read();flag[q[j]]=1;    }
        sort(q+1,q+x+1,cmp);
        for(int j=1;j<=x;++j){
            if(top==0){
                stack[++top]=q[j];
                continue;
            }
            int lca=calclca(q[j],stack[top]);
            while(dfn[lca]<dfn[stack[top]]){
                if(dfn[lca]>=dfn[stack[top-1]]){
                    add(lca,stack[top],0);
                    if(stack[--top]!=lca)    stack[++top]=lca;
                    break;
                }
                add(stack[top-1],stack[top],0);
                top--;
            }
            stack[++top]=q[j];
        }
        while(top>1){
            add(stack[top-1],stack[top],0);
            top--;
        }
        calc(stack[1],stack[1]);
        printf("%lld\n",ans[stack[1]]);
        for(int j=1;j<=x;++j)    flag[q[j]]=0;
    }
    return 0;
}

 

posted @ 2018-01-10 08:00  Konoset  阅读(179)  评论(0编辑  收藏  举报