【NOIP2021国庆集训Day1】B.逛动物园
【题意】
【分析】
显然这是一个树形的结构,我们可以发现每次连接两个操作就相当于两个子树的合并,而一个点的子树的部分一定要小于等于这个点,概率为2/3
我们可以先将整个树结构离线建立起来,然后用dfs序来将子树转换成区间,然后利用线段树解决这个问题
注意:要用vector,链式前向星的顺序是反的!
【代码】
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int mod=998244353; const int maxn=2e5+5; int n,m; // int head[maxn],tot; // struct edge // { // int to,nxt; // }e[maxn]; // void add(int x,int y) // { // e[++tot].to=y; e[tot].nxt=head[x]; head[x]=tot; // } //这里不能用链式前向星,因为一个点的儿子有顺序!!!! //!!!!! vector <int> G[maxn]; int dfn[maxn],dfstime,vis[maxn]; void dfs(int u) { dfn[u]=++dfstime; for(auto to:G[u]) dfs(to); } // int p2[maxn],p3[maxn]; int fath[maxn]; int siz[maxn]; int u[maxn],v[maxn],opt[maxn]; int qpow(int a,int b) { int res=1; while(b) { if(b&1) res=1ll*res*a%mod; a=1ll*a*a%mod; b>>=1; } return res; } int rev,total; int tr[maxn<<2]; void build(int now,int l,int r) { tr[now]=1; if(l==r) return; int mid=(l+r)>>1; build(now<<1,l,mid); build(now<<1|1,mid+1,r); } int query(int now,int l,int r,int pos) { if(l==r) return tr[now]; int mid=(l+r)>>1; if(pos<=mid) return 1ll*query(now<<1,l,mid,pos)*tr[now]%mod; else return 1ll*query(now<<1|1,mid+1,r,pos)*tr[now]%mod; } void update(int now,int l,int r,int L,int R,int val) { // if(r<L || l>R) return; if(l>=L && r<=R) { tr[now]=1ll*tr[now]*val%mod; return; } int mid=(l+r)>>1; if(L<=mid) update(now<<1,l,mid,L,R,val); if(mid<R) update(now<<1|1,mid+1,r,L,R,val); } int main() { freopen("zoo.in","r",stdin); freopen("zoo.out","w",stdout); scanf("%d%d",&n,&m); total=qpow(3,n); rev=qpow(3,mod-2); // p2[0]=p3[0]=1; // for(int i=1;i<=n;i++) fath[i]=i,p2[i]=2ll*p2[i-1]%mod,p3[i]=3ll*p3[i-1]%mod; // int op,x,y; // for(int i=1;i<=m;i++) // { // scanf("%d",&op); // if(op==1) // { // scanf("%d%d",&x,&y); // // add(x,y); // big[y]=siz[fath[y]]; // small[y]=siz[fath[]] // } // else // { // scanf("%d",&x); // for(int j=1;j<=n;j++) dep[j]=siz[j]=0; // dfs(fath[x]); // int son=siz[x]-1,fa=dep[x]; // printf("[%d %d]\n",son,fa); // int ans=0; // ans=(ans+1ll*p3[n-fa-1]*p2[fa]%mod)%mod; // ans=(ans+1ll*p3[n-fa-son-1]*p2[son]%mod)%mod; // if(!fa) ans=(ans+p3[n-son-1])%mod; // printf("%d\n",ans); // } // } for(int i=1;i<=m;i++) { scanf("%d",&opt[i]); if(opt[i]==1) { scanf("%d%d",&u[i],&v[i]); //add(u[i],v[i]); fath[v[i]]=u[i]; G[u[i]].push_back(v[i]); } else scanf("%d",&u[i]); } for(int i=1;i<=n;i++) if(!fath[i]) dfs(i); for(int i=1;i<=n;i++) siz[i]=1; build(1,1,n); // printf("%d\n",total); for(int i=1;i<=m;i++) { if(opt[i]==2) printf("%lld\n",1ll*total*query(1,1,n,dfn[u[i]])%mod); else { update(1,1,n,dfn[u[i]],dfn[u[i]]+siz[u[i]]-1,2ll*rev%mod); update(1,1,n,dfn[v[i]],dfn[v[i]]+siz[v[i]]-1,rev); siz[u[i]]+=siz[v[i]]; } } return 0; }