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

虚树第一题。

大概就是建一颗只与询问有关的更小的新树,然后在虚树上DP

#include <map>
#include <ctime>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define inf 1e17
#define maxn 500005
 
int n,m,k,a[maxn];
int h[maxn],to[maxn],ne[maxn],w[maxn],en=0;
int dep[maxn],st[maxn][21],_log[maxn],in[maxn],out[maxn],tot,ord[maxn];
ll mn[maxn];int sta[maxn],top=0,last[maxn],idx=0;
 
void add(int a,int b,int c)
{to[en]=b;ne[en]=h[a];w[en]=c;h[a]=en++;}
 
void dfs(int o,int fa)
{
    in[o]=++tot;ord[tot]=o;
    for (int i=h[o];i>=0;i=ne[i])
    if (to[i]!=fa){
        dep[to[i]]=dep[o]+1;
        mn[to[i]]=min(mn[o],(ll)w[i]);
        dfs(to[i],o);
        ord[++tot]=o;
    }
    out[o]=tot;
}
 
void initst()
{
    F(i,2,maxn-1) _log[i]=_log[i>>1]+1;
    F(i,1,20) F(j,1,tot-(1<<i)+1)
    {
        if (dep[st[j][i-1]]<dep[st[j+(1<<i-1)][i-1]]) st[j][i]=st[j][i-1];
            else st[j][i]=st[j+(1<<i-1)][i-1];
    }
}
 
int lca(int l,int r)
{
    if (l==r) return l;
    l=in[l],r=in[r];
    if (l>r) swap(l,r);
    int tmp=_log[r-l+1];// printf("tmp is %d\n",tmp);
    if (dep[st[l][tmp]]<dep[st[r-(1<<tmp)+1][tmp]]) return st[l][tmp];
    else return st[r-(1<<tmp)+1][tmp];
}
 
bool cmp(int a,int b)
{return in[a]<in[b];}
 
int hd[maxn],tl[maxn],nxt[maxn],ed,se[maxn];
 
void add_edge(int a,int b)
{
    if (last[a]!=idx) last[a]=idx,hd[a]=-1;
    tl[ed]=b;
    nxt[ed]=hd[a];
    hd[a]=ed++;
}
 
ll dfs2(int o,int fa)
{
    ll ret=0;
    for (int i=hd[o];i>=0;i=nxt[i])
        if (tl[i]!=fa)
            ret+=dfs2(tl[i],o);
    if(se[o]==idx) return mn[o];
    return min(ret,(ll)mn[o]);
}
 
int main()
{
    memset(h,-1,sizeof h);
    scanf("%d",&n); mn[1]=inf;
    F(i,1,n-1)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);add(b,a,c);
    }
    dfs(1,0);
    F(i,1,tot)st[i][0]=ord[i];initst();
    scanf("%d",&m);
    while (m--)
    {
        ed=0; idx++;
        scanf("%d",&k);
        F(i,1,k) scanf("%d",&a[i]),se[a[i]]=idx;
        sort(a+1,a+k+1,cmp);
        sta[top=1]=1;
        F(i,1,k)
        {
            int l=in[sta[top]],r=in[a[i]],x=lca(sta[top],a[i]);
            while (dep[sta[top]]>dep[x])
            {
                int tmp;
                if (dep[x]>dep[sta[top-1]]) tmp=x;
                else tmp=sta[top-1];
                add_edge(sta[top],tmp);
                add_edge(tmp,sta[top]);
                top--;
            }
            if (x!=sta[top]) sta[++top]=x;
            sta[++top]=a[i];
        }
        while (top>1) add_edge(sta[top],sta[top-1]),add_edge(sta[top-1],sta[top]),top--;
        printf("%lld\n",dfs2(1,0));
    }
}

  

posted @ 2017-04-05 18:07  SfailSth  阅读(150)  评论(0编辑  收藏  举报