[codeforces]Round #537 (Div. 2)E. Tree

题解:  q次查询每次查询k个点  k的总和不超过1e5  那就->虚树  这个题分为两部分  前面先对每次查询的点建虚树 其次计数  对于新树上的每个关键点(查询点)  他能影响的m的范围 必然大于以r为根的祖先节点的个数 然后我们单独考虑每个节点的贡献为 当前集合个数减去其祖先节点的个数  然后我们考虑把每个点按照dfs序的下标考虑贡献  转移分为两部分

      1.当前元素加入直接构成一个新集合

      2,当前元素加入可以加入到  m(当前集合个数)-祖先节点个数

#include <bits/stdc++.h>
#define ll long long
#define inc(i,l,r) for(int i=l;i<=r;i++)
const int MAXN=3e5+10;
using namespace std;
const ll inf=1e18;
const ll MOD=1e9+7;
vector<int>vec[MAXN];
int f[MAXN][21];int dep[MAXN];
int st[MAXN],tot;
int p[MAXN],cnt1;
vector<int>V;
bool vis[MAXN];
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
ll Add(ll a, ll b){a+=b;if(a>=MOD)a-=MOD; return a;}
ll Mult(ll a, ll b){return (a*b)%MOD;}
void dfs(int v,int pre,int deep){
    dep[v]=deep;f[v][0]=pre;p[v]=++cnt1;
    for(int i=0;i<vec[v].size();i++){
    int u=vec[v][i];
    if(u!=pre){
        dfs(u,v,deep+1);
    }
    }
}
void dfs1(int v){
    inc(i,1,20)f[v][i]=f[f[v][i-1]][i-1];
    for(int i=0;i<vec[v].size();i++){
    int u=vec[v][i];
    if(u!=f[v][0])dfs1(u);
    }
}
int Lca(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    int tmp=dep[u]-dep[v];
    for(int i=0;i<=20;i++)if(tmp&(1<<i))u=f[u][i];
    if(u==v)return u;
    for(int i=20;i>=0;i--){
    if(f[u][i]!=f[v][i]){
        u=f[u][i];
        v=f[v][i];
    }
    }
    return f[u][0];
}
ll dp[2][305];
void built(int x){
    V.push_back(x);
    if(!tot){st[++tot]=x;return ;}
    int lca=Lca(x,st[tot]);
    while(tot>1&&dep[lca]<dep[st[tot-1]]){
    vec[st[tot]].push_back(st[tot-1]);
    vec[st[tot-1]].push_back(st[tot]);
    tot--;
    }
    if(dep[st[tot]]>dep[lca]){
    vec[st[tot]].push_back(lca);
    vec[lca].push_back(st[tot]);
    tot--;
    V.push_back(lca);
    }
    if(!tot||dep[lca]>dep[st[tot]])st[++tot]=lca;
    st[++tot]=x;
}
int M[MAXN],St[MAXN],cnt;
void dfs2(int x,int pre,int deep){
    if(vis[x])M[x]=deep+1,St[++cnt]=x;
    for(int i=0;i<vec[x].size();i++){
	if(vec[x][i]!=pre){
	    if(vis[x])dfs2(vec[x][i],x,deep+1);
	    else dfs2(vec[x][i],x,deep);
	}
    }
}
int n,m;
bool cmp(int aa,int bb){return p[aa]<p[bb];}
int main(){
    n=read();m=read();
    int u,v;
    for(int i=1;i<n;i++)u=read(),v=read(),vec[u].push_back(v),vec[v].push_back(u);
    dfs(1,0,0);dfs1(1);int k,q,r;
    for(int i=1;i<=n;i++)vec[i].clear();
    while(m--){
    k=read();q=read();r=read();
    tot=0;
    V.push_back(r);
    for(int i=1;i<=k;i++)v=read(),V.push_back(v),vis[v]=1;
    sort(V.begin(),V.end(),cmp);
    int sz=unique(V.begin(),V.end())-V.begin();
    for(int i=1;i<=sz;i++)built(V[i-1]);
    while(tot>1){vec[st[tot]].push_back(st[tot-1]),vec[st[tot-1]].push_back(st[tot]);tot--;}
    cnt=0;dfs2(r,0,0);
    int K=0;
    inc(i,1,q)dp[K][i]=0;
    dp[K][0]=1;
    for(int i=1;i<=cnt;i++){
	K=1-K;
	inc(j,0,q)dp[K][j]=0;
	for(int j=0;j<=q;j++){
	    if(j<q)dp[K][j+1]=Add(dp[K][j+1],dp[!K][j]);
	    if(M[St[i]]<=j)dp[K][j]=Add(dp[K][j],Mult(dp[!K][j],j-M[St[i]]+1));
	}
    }
    ll ans=0;
    inc(i,1,q)ans=Add(ans,dp[K][i]);
    printf("%lld\n",ans);
    for(int i=0;i<V.size();i++)vec[V[i]].clear(),vis[V[i]]=0;
    V.clear();
    }
    return 0;
}
上一篇:第98期-基础结构:字符串 实现 strStr()


下一篇:【C++】【LeetCode】KMP算法