【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;
}

 

posted @ 2021-10-01 21:01  andyc_03  阅读(67)  评论(0编辑  收藏  举报