虚树 模板...

虚树的话,就是把有用的的结点从树中提取出来,从而不会超时的一种东西

先把点都读入进来

按照dfs序排序

在把相邻的点的LCA加入

再按照dfs序排序

然后用栈维护一条祖先后代链

然后在维护过程中退栈的时候加边就行了

bzoj_3611大工程

虚树+dp

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define rint register int
using namespace std;
char rea=0;
inline void read(int &x)
{
    x=0;
    while(rea<'0'||rea>'9') rea=getchar();
    while(rea>='0'&&rea<='9') x=x*10+rea-'0',rea=getchar();
}
const int N=1000006;
const ll Inf=1e12;
int first[N],nt[N<<1],ver[N<<1],e;
inline void addbian(int u,int v)
{
    ver[e]=v;
    nt[e]=first[u];
    first[u]=e++;
}

int n,m;
int timer,vis[N],t[N],con,root;
int isk[N];
int fa[N],dep[N],st[N][30],maxk,dfn[N],tim,qi[N],ho[N];
void dfs(int x)
{
    dfn[x]=++tim; qi[x]=tim;
    int i;
    for(i=first[x];i!=-1;i=nt[i])
    {
        if(ver[i]==fa[x])    continue;
        fa[ver[i]]=x;
        dep[ver[i]]=dep[x]+1;
        dfs(ver[i]);
    }
    ho[x]=tim;
}
void ST()
{
    while((1<<maxk)<=n) ++maxk; --maxk;
    int i,j;
    mem(st,-1);
    for(i=1;i<=n;++i)
        st[i][0]=fa[i];
    for(j=1;(1<<j)<=n;++j)
        for(i=1;i<=n;++i)
            if(st[i][j-1]!=-1)
                st[i][j]=st[st[i][j-1]][j-1];
}
int LCA(int x,int y)
{
    if(dep[x]<dep[y]) x^=y,y^=x,x^=y;
    int i;
    for(i=maxk;~i;--i)
        if(dep[x]-(1<<i)>=dep[y])
            x=st[x][i];
    if(x==y) return x;
    for(i=maxk;~i;--i)
        if(st[x][i]!=-1&&st[x][i]!=st[y][i])
            x=st[x][i],y=st[y][i];
    return fa[x];
}

struct T0v0T
{
    int first[N],nt[N<<1],ver[N<<1],e;
    void clear()
    {
        int i; e=0;
        for(i=1;i<=con;++i) first[t[i]]=-1;
    }
    inline void addbian(int u,int v)
    {
        ver[e]=v;
        nt[e]=first[u];
        first[u]=e++;
    }
}h;

int zhan[N],he;
bool cmp(int a,int b)
{
    return dfn[a]<dfn[b];
}
ll mndep[N],mxdep[N],mnan[N],mxan[N],size[N];
ll sum[N],ansum;
void dp(int x,int prr)
{
    size[x]=0; if(isk[x]==timer) size[x]=1;
    mndep[x]=Inf; if(isk[x]==timer) mndep[x]=dep[x];
    mxdep[x]=0; if(isk[x]==timer) mxdep[x]=dep[x];
    mnan[x]=Inf; mxan[x]=0;
    sum[x]=0; if(isk[x]==timer) sum[x]=dep[x];
    int i,te; ll tt=0,mn=Inf,mn2=Inf,mx=0,mx2=0;
    for(i=h.first[x];i!=-1;i=h.nt[i])
        if(h.ver[i]!=prr)
        {
            dp(h.ver[i],x);
            sum[x]+=sum[h.ver[i]];
            size[x]+=size[h.ver[i]];
            if(mn>mndep[h.ver[i]])
            {
                mn2=mn;
                mn=mndep[h.ver[i]];
            }
            else
                if(mn2>mndep[h.ver[i]])
                    mn2=mndep[h.ver[i]];
            if(mx<mxdep[h.ver[i]])
            {
                mx2=mx;
                mx=mxdep[h.ver[i]];
            }
            else
                if(mx2<mxdep[h.ver[i]])
                    mx2=mxdep[h.ver[i]];
        }
    
    if(isk[x]==timer)
    {
        tt+=1LL*(size[x]-1)*dep[x];
        tt+=1LL*(1)*(sum[x]-dep[x]);
        tt-=1LL*dep[x]*2*(1)*(size[x]-1);
    }
    for(i=h.first[x];i!=-1;i=h.nt[i])
        if(h.ver[i]!=prr)
        {
            tt+=1LL*(size[x]-size[h.ver[i]])*sum[h.ver[i]];
            tt+=1LL*size[h.ver[i]]*(sum[x]-sum[h.ver[i]]);
            tt-=1LL*dep[x]*2*(size[h.ver[i]])*(size[x]-size[h.ver[i]]);
        }
    ansum+=tt/2;
    if(isk[x]==timer)
    {
        if(mn>dep[x])
        {
            mn2=mn;
            mn=dep[x];
        }
        else
            if(mn2>dep[x])
                mn2=dep[x];
        if(mx<dep[x])
        {
            mx2=mx;
            mx=dep[x];
        }
        else
            if(mx2<dep[x])
                mx2=dep[x];
    }
    mndep[x]=mn; mxdep[x]=mx;
    mnan[x]=mn+mn2-2*dep[x];
    mxan[x]=mx+mx2-dep[x]*2;
}
void work()
{
    rint i,j; int ycon=con,tt;
    sort(t+1,t+1+con,cmp);
    for(i=1;i<ycon;++i)
    {
        tt=LCA(t[i],t[i+1]);
        if(vis[tt]!=timer)
            t[++con]=tt,vis[tt]=timer;
    }
    sort(t+1,t+1+con,cmp);
    he=0; h.clear();
    
    for(i=1;i<=con;++i)
    {
        if(!he) zhan[++he]=t[i];
        else
        {
            while(he>1&&!(qi[t[i]]>=qi[zhan[he]]&&ho[t[i]]<=ho[zhan[he]]))
                h.addbian(zhan[he-1],zhan[he]),--he;
            zhan[++he]=t[i];
        }
    }
    while(he>1) h.addbian(zhan[he-1],zhan[he]),--he;
    root=zhan[1];
    
    
    ansum=0;
    dp(root,-1);
    
    ll mn=Inf,mx=0;
    for(i=1;i<=con;++i)
    {
        if(mn>mnan[t[i]]) mn=mnan[t[i]];
        if(mx<mxan[t[i]]) mx=mxan[t[i]];
    }
    printf("%lld %lld %lld\n",ansum,mn,mx);
}

int main(){
    
  //freopen("in.in","r",stdin);
    //freopen("out.out","w",stdout);
    
    rint i,j; int tin1,tin2,Q,K,tin;
    mem(first,-1);
    
    read(n);
    for(i=1;i<n;++i)
    {
        read(tin1); read(tin2);
        addbian(tin1,tin2);
        addbian(tin2,tin1);
    }
    fa[1]=-1; dfs(1);
    ST();
    read(Q);
    for(i=1;i<=Q;++i)
    {
        read(K); ++timer; con=0;
        for(j=1;j<=K;++j)
            ++con,read(t[con]),vis[t[con]]=timer,isk[t[con]]=timer;
        if(K<2)
        {
            printf("0 0 0\n");
            continue;
        }
        work();
    }
}
bzoj_3611

bzoj_2286消耗战

虚树+dp

最小值要用倍增,树链剖分会T

开long long

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define rint register int
using namespace std;
char rea=0;
inline void read(int &x)
{
    x=0;
    while(rea<'0'||rea>'9') rea=getchar();
    while(rea>='0'&&rea<='9') x=x*10+rea-'0',rea=getchar();
}
const int N=250006;
const int Inf=2e9;
const ll llInf=1e15;
int first[N],w[N<<1],nt[N<<1],ver[N<<1],e;
void addbian(int u,int v,int _w)
{
    ver[e]=v; w[e]=_w;
    nt[e]=first[u];
    first[u]=e++;
}

int n,m,K;
int maxk;
int t[N],con;
int zhan[N],he;
int vis[N],timer;

int fa[N],dep[N],v[N];
int dfn[N],tim,qi[N],ho[N];

int st[N][30],mn[N][30];

void dfs1(int x)
{
    dfn[x]=qi[x]=++tim;
    int i;
    for(i=first[x];i!=-1;i=nt[i])
        if(ver[i]!=fa[x])
        {
            fa[ver[i]]=x;
            dep[ver[i]]=dep[x]+1;
            v[ver[i]]=w[i];
            dfs1(ver[i]);
        }
    ho[x]=tim;
}
void ST()
{
    while((1<<maxk)<=n) ++maxk; --maxk;
    rint i,j;
    mem(st,-1); mem(mn,0x7f);
    for(i=1;i<=n;++i)
        st[i][0]=fa[i],mn[i][0]=v[i];
    for(j=1;(1<<j)<=n;++j)
        for(i=1;i<=n;++i)
            if(st[i][j-1]!=-1)
                st[i][j]=st[st[i][j-1]][j-1],
                mn[i][j]=min(mn[i][j-1],mn[st[i][j-1]][j-1]);
}
int LCA(int x,int y)
{
    int i;
    if(dep[x]<dep[y]) x^=y,y^=x,x^=y;
    for(i=maxk;~i;--i)
        if(dep[x]-(1<<i)>=dep[y])
            x=st[x][i];
    if(x==y) return x;
    for(i=maxk;~i;--i)
        if(st[x][i]!=-1&&st[x][i]!=st[y][i])
            x=st[x][i],y=st[y][i];
    return fa[x];
}
int MN(int x,int y)
{
    int i,an=Inf;
    if(dep[x]<dep[y]) x^=y,y^=x,x^=y;
    for(i=maxk;~i;--i)
        if(dep[x]-(1<<i)>=dep[y])
        {
            if(an>mn[x][i]) an=mn[x][i];
            x=st[x][i];
        }
    if(x==y) return an;
    for(i=maxk;~i;--i)
        if(st[x][i]!=-1&&st[x][i]!=st[y][i])
        {
            if(an>mn[x][i]) an=mn[x][i];
            if(an>mn[y][i]) an=mn[y][i];
            x=st[x][i],y=st[y][i];
        }
    if(an>mn[x][0]) an=mn[x][0];
    if(an>mn[y][0]) an=mn[y][0];
    return an;
}

struct T0x0T
{
    int first[N],w[N<<1],nt[N<<1],ver[N<<1],e;
    void clear()
    {
        int i; e=0;
        for(i=1;i<=con;++i)
            first[t[i]]=-1;
    }
    void addbian(int u,int v,int _w)
    {
        ver[e]=v; w[e]=_w;
        nt[e]=first[u];
        first[u]=e++;
    }
}h;

ll f[N]; int isk[N],sz[N];
void dp(int x)
{
    //printf("x=%d\n",x);
    f[x]=0;
    int i;
    for(i=h.first[x];i!=-1;i=h.nt[i])
    {
        //printf("x=%d ver=%d w=%d\n",x,h.ver[i],h.w[i]);
        dp(h.ver[i]);
        if(isk[h.ver[i]]==timer)
            f[x]+=h.w[i];
        else
            f[x]+=min((ll)h.w[i],f[h.ver[i]]);
    }
}

bool cmp(int a,int b)
{
    return dfn[a]<dfn[b];
}
void work()
{
    sort(t+1,t+1+con,cmp); rint i; int tt,t1;
    tt=con;
    for(i=1;i<tt;++i)
    {
        t1=LCA(t[i],t[i+1]);
        if(vis[t1]!=timer) t[++con]=t1,vis[t1]=timer;
    }
    sort(t+1,t+1+con,cmp);
    he=0; h.clear();
    for(i=1;i<=con;++i)
    {
        if(!he) zhan[++he]=t[i];
        else
        {
            while( he>1 && (!(qi[zhan[he]]<=qi[t[i]]&&ho[zhan[he]]>=ho[t[i]])) )
                h.addbian(zhan[he-1],zhan[he],MN(zhan[he-1],zhan[he])),--he;
            zhan[++he]=t[i];
        }
    }
    while(he>1)
        h.addbian(zhan[he-1],zhan[he],MN(zhan[he-1],zhan[he])),--he;
    
/*    printf("\n");
    for(i=1;i<=con;++i)
        printf("%d ",t[i]);
    printf("\n");*/
    
    dp(1);
    printf("%lld\n",f[1]);
}

int main(){
    
    //freopen("in.in","r",stdin);
    //freopen("out.out","w",stdout);
    
    rint i,j; int tin1,tin2,tin3;
    mem(first,-1);
    
    read(n);
    for(i=1;i<n;++i)
    {
        read(tin1); read(tin2); read(tin3);
        addbian(tin1,tin2,tin3);
        addbian(tin2,tin1,tin3);
    }
    fa[1]=-1; dfs1(1);
    ST();
    
    read(m);
    for(i=1;i<=m;++i)
    {
        read(K); con=0; ++timer;
        t[++con]=1; vis[1]=timer;
        for(j=1;j<=K;++j)
            ++con,read(t[con]),vis[t[con]]=timer,isk[t[con]]=timer;
        work();
    }
}
bzoj_2286

 

posted @ 2017-10-30 18:56  A_LEAF  阅读(200)  评论(0编辑  收藏  举报