数据结构入门9—虚树

来源:互联网 发布:红警2尤复简体优化版 编辑:程序博客网 时间:2024/06/01 08:56

原本以为K-D Tree比虚树难,但是后来发现虚树反而难理解一些。主要是关于找LCA的问题。

假如我们有一些点是一定要在虚树里的,那么需要保证他们任意两点的LCA也在虚树里,否则树的结构就改变了。

那么就需要用到dfs序了。

我们求得每个点的dfs序,然后把这些点按dfs序排序,那么他们所有的LCA肯定是排序后某相邻两点的LCA。这个是可以证明的,我就不证了。

然后找到LCA之后就是找每个节点的虚树父亲问题了,把找到的新节点(就是找到的LCA)与原来所有节点一起按照dfs序再排一次序,因为我们可以在初始化时找出每个点所在子树的最大最小时间戳,所以可以维护一个栈然后判断当前节点是否为栈内节点的原图中的子孙,若不是就弹栈,否则就是我们要找的父亲。

模板题链接

//Serene#include<algorithm>#include<iostream>#include<cstring>#include<cstdlib>#include<cstdio>#include<cmath>#include<set>using namespace std;const long long maxn=250000+10,INF=2e9;long long n,m,mi[20]; long long dp[maxn],len[maxn],node[maxn],zz[maxn];int vis[maxn],fath[maxn];  long long aa;char cc;long long read() {    aa=0;cc=getchar();    while(cc<'0'||cc>'9') cc=getchar();    while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();    return aa;} int fir[maxn],nxt[2*maxn],to[2*maxn];long long v[2*maxn],e=0;void add(int x,int y,int z) {    to[++e]=y;nxt[e]=fir[x];fir[x]=e;v[e]=z;    to[++e]=x;nxt[e]=fir[y];fir[y]=e;v[e]=z;} int fa[maxn][20],id[maxn],end[maxn],dep[maxn],tot,maxd;void dfs(int pos,int d,long long minnum) {    dep[pos]=d;id[pos]=++tot;len[pos]=minnum;    maxd=max(maxd,d);    for(int y=fir[pos];y;y=nxt[y]) {        if(to[y]==fa[pos][0]) continue;        fa[to[y]][0]=pos;        dfs(to[y],d+1,min(v[y],minnum));    }    end[pos]=tot;} bool cmp(const int x,const int y) {    return id[x]<id[y];} int getlca(int x,int y) {    if(dep[x]!=dep[y]) {        if(dep[x]<dep[y]) swap(x,y);        int cha=dep[x]-dep[y];        for(int i=18;i>=0;--i) if(mi[i]<=cha){            cha-=mi[i]; x=fa[x][i];            if(!cha) break;        }    }    int xx,yy,z;    while(x!=y) {        xx=x; yy=y; z=0;        while(xx!=yy) {            x=xx; y=yy;            xx=fa[xx][z];yy=fa[yy][z];            z++;        }        if(z==1) { x=xx; y=yy; }    }    return x;} int main() {    n=read();    int x,y,z,xx;    for(int i=1;i<n;++i) {        x=read();y=read();z=read();        add(x,y,z);    }    dfs(1,1,INF);    mi[0]=1;for(int i=1;i<=18;++i) mi[i]=mi[i-1]*2;    for(int i=1;mi[i]<=maxd+1;++i) for(int j=1;j<=n;++j) fa[j][i]=fa[fa[j][i-1]][i-1];    m=read();    for(int qaq=1;qaq<=m;++qaq) {        x=read();        for(int i=1;i<=x;++i) node[i]=read(),vis[node[i]]=1;        sort(node+1,node+x+1,cmp);        xx=x;//        for(int i=2;i<=xx;++i) {            z=getlca(node[i-1],node[i]);            if(!vis[z]) node[++x]=z,vis[z]=2;        }        if(!vis[1]) node[++x]=1,vis[1]=2;        sort(node+1,node+x+1,cmp);        y=1;zz[1]=node[1];dp[node[1]]=0;        for(int i=2;i<=x;++i) {            dp[node[i]]=len[node[i]];            while(y&&id[node[i]]>end[zz[y]]) y--;            fath[node[i]]=zz[y];dp[zz[y]]=0;            zz[++y]=node[i];//        }        for(int i=x;i>1;i--) {            if(vis[node[i]]==2) dp[node[i]]=min(dp[node[i]],len[node[i]]);//            else dp[node[i]]=len[node[i]];            dp[fath[node[i]]]+=dp[node[i]];        }        printf("%lld\n",dp[node[1]]);        for(int i=1;i<=x;++i) vis[node[i]]=0;    }    return 0;}