Xushuluejie

ディレクトリ

仮想ツリー

問題ツリーのクラスの治療

このような質問は、ポイント数は、ツリーのポイント数よりもはるかに小さい尋ねる、いくつかの側面と一緒にカウントすることができます

その後、我々はそれに唯一のポイントを保持する必要があります

明らかに、キーポイントと変曲点(一部はLCAあり)

二十から二LCAおよび重量を得るために全ての点の仮想ツリーで得ることができる、DFSソート順に従って各点を考えます

の構築

私たちは、スタックと内部単調なシーケンスDFSによって増分スタック要素をコンクリートの建物を達成します

すべてのキーのDFSオーダーへのアクセスをクリックして、各点のために追加される\(のP- \)、2つのケースがあります。

  1. \(P \)及び頂部要素は、\(X \) LCAである(X \)を\、説明\(P \)における(X \)\内部スタックサブツリー
  2. それ以外の場合は、特定のアクセスのサブツリーの最上位要素は、(順番DFS)完了し、建物を考えます

頂部要素が設けられている\(X \) 第二の要素である\(Y \)

  • もし\(DFN [Y]> DFN [LCA] \) 接続されていてもよい側\(Y \) - > \(X \) \(X \)スタックのうち。
  • もし\(DFN [Y] = DFN [LCA] \) すなわち\(LCA Y = \) 偶数側$ lca->のx $、この時間\(LCA(Y)\)サブツリーは、建物を終えました。
  • もし\(DFN [Y] <DFN [LCA] \) すなわち\(LCA \)\(Y、X \)も側との間の\(LCA-> X \)、\ (X \)のうちスタック、その後、\(LCA \)スタック。このサブツリーで、LCA(BREAK)の構築が完了

コード:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
const int N = 1000010,M=2000010,K = 23,inf=192608170;
using namespace std;
int n;
inline int read(){
    int x=0,pos=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return pos?x:-x;
}
struct node{
    int v,nex;
};
ll ans1,ans2,f[N],maxs[N],mins[M],sz[N]; 
int fa[N][23],dfn[N],tim,bo[N],pi[N],st[N],dep[N],dis[N],num,bq[N];
struct graph{
    node edge[M];int top,head[N];
    void add(int u,int v){
        edge[++top].v=v;edge[top].nex=head[u];head[u]=top;
    }
    void dfs1(int x){
        dfn[x]=++tim;
        for(int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
        for(int i=head[x];i;i=edge[i].nex){
            int v=edge[i].v;
            if(v!=fa[x][0])
                dis[v]=dis[x]+1,dep[v]=dep[x]+1,fa[v][0]=x,dfs1(v);
        }
    }
    void dfs2(int x){
        sz[x]=bo[x],maxs[x]=0,mins[x]=inf,f[x]=0;
        for(int i=head[x];i;i=edge[i].nex){
            int v=edge[i].v,d=dis[v]-dis[x];
            dfs2(v);sz[x]+=sz[v];
            ans1=min(ans1,mins[x]+mins[v]+d),ans2=max(ans2,maxs[x]+maxs[v]+d);
            mins[x]=min(mins[x],mins[v]+d),maxs[x]=max(maxs[x],maxs[v]+d); 
            f[x]+=f[v]+1ll*d*(num-sz[v])*sz[v];
        }
        if(bo[x]) ans1=min(ans1,mins[x]),ans2=max(ans2,maxs[x]),mins[x]=0;
        head[x]=0;
    }
}g1,g2;
int q;
int cmp(int a,int b){
    return dfn[a]<dfn[b];
}
int lca(int a,int b){
    if(dep[a]<dep[b]) swap(a,b);
    for(int h=dep[a]-dep[b],i=20;i>=0;i--){
        if(h>=(1<<i)){
            h-=(1<<i);
            a=fa[a][i];
        }
    }
    if(a==b) return a;
    for(int i=20;i>=0;i--) if(fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i];
    return fa[a][0];
}
void work(){
    sort(pi+1,pi+num+1,cmp);
    int tp=0;
    for(int i=1;i<=num;i++){
        if(!tp){
            st[++tp]=pi[i];continue;
        }
        int u=lca(st[tp],pi[i]);
        while(dfn[u]<dfn[st[tp]]){
            if(dfn[u]>=dfn[st[tp-1]]){
                g2.add(u,st[tp]);
                if(st[--tp]!=u) st[++tp]=u;
                break;
            }
            g2.add(st[tp-1],st[tp]);tp--;
        }
        st[++tp]=pi[i];
    }
    while(tp>1) g2.add(st[tp-1],st[tp]),tp--;
    ans1=inf,ans2=0,g2.dfs2(st[1]);
    printf("%lld %d %d\n",f[st[1]],ans1,ans2);
    for(int i=1;i<=num;i++) bo[pi[i]]=0;
    for(int i=1;i<=g2.top;i++) g2.edge[i].nex=g2.edge[i].v=0;g2.top=0;
}
int main(){
    n=read();g1.top=g2.top=0;
    for(int i=1,u,v;i<n;i++){
        u=read(),v=read();
        g1.add(u,v);g1.add(v,u); 
    }
    g1.dfs1(1);q=read();
    for(int i=1;i<=q;i++){
        num=read();
        for(int j=1;j<=num;j++){
            pi[j]=read();bo[pi[j]]=1; 
        } 
        work();
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/lcyfrog/p/11586210.html