Bzoj2286--Sdoi2011消耗战

栈模拟dfs,学到了新姿势

这种题很显然应该用虚树去搞,之前也没写过虚树

具体来说就是先维护dfs序,之后每次询问按dfs序排序后一个一个压入栈内,相当于dfs中的进入递归

如果当前压入栈中的元素与之前栈顶元素的Lca深度小于栈顶元素,那么就把栈顶元素弹出,相当于dfs中的返回

虚树上就很好dp了,在模拟dfs时就可以完成dp

代码 :

#include<bits/stdc++.h>
#define LL long long 
#define low(x) (x&(-x))
#define LNF 1000000000000000
using namespace std;
inline int _max(int a,int b) {return a>b?a:b;}
inline LL _min(LL a,LL b) {return a<b?a:b;}

#define MAXN 250005
#define MAXM 500005

int n,m,k,q[MAXN];LL ans;
int st[MAXN],top;

int head[MAXN],cnt;
struct Edge{
    int to,next,w;
}e[MAXM];
inline void insert(int a,int b,int c) {
    e[++cnt].next=head[a];head[a]=cnt;e[cnt].to=b;e[cnt].w=c;
    e[++cnt].next=head[b];head[b]=cnt;e[cnt].to=a;e[cnt].w=c;
}

int dep[MAXN],bz[MAXN][22],mi[MAXN][22],ds[MAXN],ind;
void dfs(int v,int fr) {
    ds[v]=++ind;dep[v]=dep[fr]+1;bz[v][0]=fr;
    for(int i=head[v];i;i=e[i].next) 
        if(!ds[e[i].to]) {
            mi[e[i].to][0]=e[i].w;
            dfs(e[i].to,v);
        }
}

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

int Lca(int a,int b) {
    if(dep[a]<dep[b]) swap(a,b);
    for(int i=20;~i;i--) if(dep[bz[a][i]]>=dep[b]) a=bz[a][i];
    for(int i=20;~i;i--) if(bz[a][i]!=bz[b][i]) a=bz[a][i],b=bz[b][i];
    return a==b?a:bz[a][0];
}

LL dis(int a,int b) {
    LL ret=LNF;
    for(int i=20;~i;i--) if(dep[bz[a][i]]>=dep[b]) 
        ret=_min(ret,mi[a][i]),a=bz[a][i];
    return ret;
}

LL dp[MAXN];bool g[MAXN];
void solve() {
    st[++top]=1;
    for(int i=1;i<=k;i++) g[q[i]]=1;
    for(int now,t,i=1;i<=k;i++) {
        now=q[i];t=Lca(now,st[top]);
        while(dep[t]<dep[st[top]]) {
            if(dep[st[top-1]]<=dep[t]) {
                dp[t]+=_min(g[st[top]]?LNF:dp[st[top]],dis(st[top],t));
                g[st[top]]=dp[st[top]]=0;top--;
                if(st[top]!=t) st[++top]=t;
                break;
            }
            else {
                dp[st[top-1]]+=_min(g[st[top]]?LNF:dp[st[top]],dis(st[top],st[top-1]));
                g[st[top]]=dp[st[top]]=0;top--;
            }
        }
        if(st[top]!=now) st[++top]=now;
    }
    while(top>1) {
        dp[st[top-1]]+=_min(g[st[top]]?LNF:dp[st[top]],dis(st[top],st[top-1]));
        dp[st[top]]=g[st[top]]=0;top--;
    }
    printf("%lld\n",dp[top--]);dp[1]=0;
}

int main() {
    scanf("%d",&n);
    for(int a,b,c,i=1;i<n;i++) {
        scanf("%d%d%d",&a,&b,&c);
        insert(a,b,c);
    }
    memset(mi,0x3f3f,sizeof(mi));
    dfs(1,0);
    for(int i=1;i<=20;i++) for(int j=1;j<=n;j++) 
        bz[j][i]=bz[bz[j][i-1]][i-1],mi[j][i]=_min(mi[j][i-1],mi[bz[j][i-1]][i-1]);
    scanf("%d",&m);
    while(m--) {
        scanf("%d",&k);ans=0;
        for(int i=1;i<=k;i++) scanf("%d",&q[i]);
        sort(q+1,q+k+1,cmp);
        solve();
    }
    return 0;
}

 

posted @ 2016-10-21 09:20  ihopenot  阅读(505)  评论(1编辑  收藏  举报