题解: 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; }
[codeforces]Round #537 (Div. 2)E. Tree
原文:https://www.cnblogs.com/wang9897/p/10352125.html