虚树

适用题目特征

树上有若干关键点(每次询问给出若干关键点),且关键点的总数是与树大小同阶,也就是说实际上一次询问中关键点对于整棵树来说是很稀疏的,所以需要让复杂度由关键点的总数来决定。即把一整颗大树浓缩成一颗小树。

原理

仅包含关键点和他们的LCA的树不会丢失信息。

例题

Luogu P2495
代码如下

/*
Luogu P2495
*/
#define method_1
#ifdef method_1
/*

*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<=(s);i--)
using namespace std;
typedef long long ll;
typedef pairpii;
const int maxn=250000+5;
const int maxlogn=23;
const int maxm=500000+5;
const ll INF=0x3f3f3f3f3f3f3f3fll;
int n,m;
int t;
int head[maxn],tot=1;
int head2[maxn],tot2;
struct node{
    int from,to;ll w;
}edge[maxm<<1],edge2[maxm<<1];
void add(int from,int to,ll w){
    edge[++tot].from=head[from];
    edge[tot].to=to,edge[tot].w=w,head[from]=tot;
}
void add2(int from,int to){
    edge2[++tot2].from=head2[from];
    edge2[tot2].to=to,head2[from]=tot2;
}
ll mn[maxn];
int d[maxn],f[maxn][maxlogn];
int dfn[maxn],cnt=0;
void dfs(int x){
    dfn[x]=++cnt;
    rep(j,1,t) f[x][j]=f[f[x][j-1]][j-1];
    for(int i=head[x];i;i=edge[i].from){
        int y=edge[i].to;ll w=edge[i].w;
        if(dfn[y]) continue;
        d[y]=d[x]+1,mn[y]=min(mn[x],w),f[y][0]=x;
        dfs(y);
    }
} 
int lca(int x,int y){
    if(d[x]>d[y]) swap(x,y);
    rrep(i,t,0) if(d[f[y][i]]>=d[x]) y=f[y][i];
    if(x==y) return x;
    rrep(i,t,0) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
int tr[maxn],q[maxn];
ll dp(int x){ //edge in virtural tree is direct, so don't need to consider edge like 
    ll sum=0ll,res;
    for(int i=head2[x];i;i=edge2[i].from){
        int y=edge2[i].to;
        sum+=dp(y);
    }
    if(q[x]) res=mn[x];
    else res=min(mn[x],sum); //cut one edge on [1,x] or cut all child of i from i
    q[x]=0,head2[x]=0;
    return res;
}
bool cmp(int x,int y){
    return dfn[x]=d[st[top-1]]){
                if(p!=st[top]){
                    add2(p,st[top]);
                    if(p!=st[top-1]) st[top]=p;
                    else top--;
                }
                break;
            }
            else add2(st[top-1],st[top]),top--;
        }
        st[++top]=now;
    }
    while(--top) add2(st[top],st[top+1]);
}
void solve(){
    t=(int)(log(n)/log(2))+1; 
    mn[1]=INF;d[1]=1;
    dfs(1);
//  rep(i,1,n) D(d[i]);E;
    scanf("%d",&m);
    int num;
    while(m--){ 
        scanf("%d",&num);
        rep(i,1,num) scanf("%d",&tr[i]),q[tr[i]]=1;
        build(num);
        ll res=dp(st[1]);
        printf("%lld\n",res);
    }
}
int main() {
//  ios::sync_with_stdio(false);
//  freopen("消耗战.in","r",stdin);
    scanf("%d",&n);
    int from,to;ll w;
    rep(i,1,n-1) scanf("%d%d%lld",&from,&to,&w),add(from,to,w),add(to,from,w);
    solve();
    return 0;
}
#endif
#ifdef method_2
/*

*/

#endif
#ifdef method_3
/*

*/

#endif

你可能感兴趣的:(虚树)