1. 程式人生 > >[codeforces]Round #537 (Div. 2)E. Tree

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

define 當前 inf () clear != dfs cmp vector

題解: 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