学习笔记--虚树

基本上就是把一棵很大的树压缩一波成一棵比较小的树,然后对原树的询问就可以在这棵压缩信息的树上搞,以降低复杂度。

构建方法:见大佬博客https://www.cnblogs.com/zzqsblog/p/5560645.html

                                    https://www.cnblogs.com/chenhuan001/p/5639482.html

                                    大致就用栈维护之前一个点为结尾的dfs链,然后分情况讨论

例题:洛谷2495 [SDOI2011]消耗战

链接:https://www.luogu.org/problemnew/show/P2495

代码:

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define ll long long
#define fi first
#define sc second
#define pii pair<int,int>
using namespace std;
const int N=300010;
void read(int &x)
{
    char c=getchar();x=0;
    while(!isdigit(c))c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+c-48,c=getchar();
}
vector<pii>mp[N];
int n,jp[N][20],mn[N][20],dfn[N],dep[N],tim=0;
void dfs(int pos,int fa,int tf)
{
    dfn[pos]=++tim,dep[pos]=dep[fa]+1;
    jp[pos][0]=fa,mn[pos][0]=tf;
    for(int i=1;i<=19;i++)
        jp[pos][i]=jp[jp[pos][i-1]][i-1],mn[pos][i]=min(mn[pos][i-1],mn[jp[pos][i-1]][i-1]);
    for(int i=0;i<mp[pos].size();i++)
        if(mp[pos][i].fi!=fa)dfs(mp[pos][i].fi,pos,mp[pos][i].sc);		
}
int lca(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    for(int i=19;i>=0;i--)
        if(dep[jp[x][i]]>=dep[y])x=jp[x][i];
    if(x==y)return x;
    for(int i=19;i>=0;i--)
        if(jp[x][i]!=jp[y][i])x=jp[x][i],y=jp[y][i];
    return jp[x][0];
}
int dis(int x,int fx)
{
    int res=2e9;
    for(int i=19;i>=0;i--)
        if(dep[jp[x][i]]>=dep[fx])
            res=min(res,mn[x][i]),x=jp[x][i];
    return res;
}
namespace Fake_tree{
    int k,imp[N],S[N],D[N],hd,fa[N];bool lab[N];
    vector<int>bin;ll ans[N];
    bool cmp(int x,int y)
    {return dfn[x]<dfn[y];}
    void build()
    {
        int tt=k,nw,f;
        sort(imp+1,imp+k+1,cmp);hd=0;
        for(int i=1;i<=k;i++)
        {
            nw=imp[i];
            if(!hd){fa[nw]=0,S[++hd]=nw;continue;}
            f=lca(nw,S[hd]);
            while(dep[S[hd]]>dep[f])
            {
                if(dep[S[hd-1]]<dep[f])fa[S[hd]]=f;
                --hd;
            }
            if(f!=S[hd])
            {
                imp[++tt]=f;
                fa[f]=S[hd];
                S[++hd]=f;
            }
            fa[nw]=f,S[++hd]=nw;
        }
        k=tt;sort(imp+1,imp+k+1,cmp);
    }
    void dfs()
    {
        int nw;
        for(int i=1;i<=k;i++)ans[imp[i]]=0;
        for(int i=k;i>=2;i--)nw=imp[i],ans[fa[nw]]+=(lab[nw]?D[nw]:min((ll)D[nw],ans[nw]));
    }
    void main()
    {
        read(k);
        for(int i=0;i<bin.size();i++)lab[bin[i]]=0;
        bin.clear();imp[1]=1,lab[1]=1,++k;
        for(int i=2;i<=k;i++)
            read(imp[i]),lab[imp[i]]=1,bin.push_back(imp[i]);
        build();
        for(int i=2;i<=k;i++)D[imp[i]]=dis(imp[i],fa[imp[i]]);dfs();
        printf("%lld\n",ans[1]);
    }
}
int main()
{
    int m,u,v,w;
    read(n);
    for(int i=1;i<n;i++)
    {
        read(u),read(v),read(w);
        mp[u].push_back(pii(v,w)),
        mp[v].push_back(pii(u,w));
    }
    dfs(1,0,0);
    read(m);
    for(int i=1;i<=m;i++)
        Fake_tree::main();
}

猜你喜欢

转载自blog.csdn.net/caoyang1123/article/details/82192758