题目传送门

思路: 

      按照题意描述,所有y挑战x的关系最后会形成一棵树的结构,n个人的总方案数是 3种,假设一个人被挑战(主场作战)a次,挑战别人(客场)b次,那么这个人存活到最后的方案数就是3n*(2/3)a*(1/3)b

      也就是我们知道这个a和b就可以得到答案了,那要怎么维护呢。

      这里用到并查集(jls niub!)

       我们用w表示一个节点总共比赛的场次数,v表示主场作战的场次数,如果我们现在把y这个集合并向x这个集合(y挑战x),那么对于XW和Xv肯定都加一,而Yw也加一,如果我们接下来能很好的合并这些信息,那我们就AC了。

      这里想了很久,才想明白要怎么做。我们先考虑暴力一点的并查集,就是不路径压缩,那每个节点就可以向上把所有父节点的信息全部加起来,就是我们最后要的某一个节点的W和V了,但是这样做会TLE,因为我们没有路径压缩,查找的时间复杂度很可能退化成O(n),但是我们又不能路径压缩(为什么不行,大家可以尝试一下,反正我自闭了一下午加一晚上)。

      普通的带权并查集我们用的都是路径压缩版本的,而这里我们要按秩合并,这样查找的时间复杂度就可以被优化到O(logn)。

曾经我一直以为带权并查集的路径压缩和按秩合并是同一个东西,这道题真的学到了。。

 

#include<bits/stdc++.h> 
#define CLR(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=200010;
int fa[maxn],Rank[maxn];
ll w[maxn],v[maxn];
int n,m;
int op,x,y;
ll p= 998244353;
struct node{
    int fx;
    ll w,v;
};
ll qpow(ll a,ll b){
    a%=p;
    ll res=1;
    while(b>0)
    {
        if(b&1){
            res*=a;
            res%=p;
        }
        b>>=1;
        a=a*a%p;
    }
    return res;
}
void init(){
    for(int i=1;i<=n;i++){
        fa[i]=i;
        w[i]=0;
        v[i]=0;
        Rank[i]=0;
    }
}
node find(int x){
    if(x==fa[x]) return {fa[x],w[x],v[x]};
    
    int tep=fa[x];
    node e;
    e.w=w[x],e.v=v[x];
    while(tep!=fa[tep]){
        e.w+=w[tep],e.v+=v[tep];
        tep=fa[tep];
    }
    e.fx=tep;
    e.v+=v[tep],e.w+=w[tep];
    return e;
}

void baba(int x,int y){
    node ex=find(x),ey=find(y);
    if(ex.fx!=ey.fx){
        w[ex.fx]+=1;
        v[ex.fx]+=1;
        w[ey.fx]+=1;
        v[ey.fx]+=0;
        if(Rank[ex.fx]>=Rank[ey.fx])
        {
            w[ey.fx]-=w[ex.fx];
            v[ey.fx]-=v[ex.fx];
            fa[ey.fx]=ex.fx;
            Rank[ex.fx]++;
        }else{
            w[ex.fx]-=w[ey.fx];
            v[ex.fx]-=v[ey.fx];
            fa[ex.fx]=ey.fx;
            Rank[ey.fx]++;
        }

    }
}
int main(){
    while(cin>>n>>m)
    {
        init();
        ll res=qpow(3,n);
        ll ans;
        while(m--)
        {
            scanf("%d%d",&op,&x);
            if(op==1){
                scanf("%d",&y);
                baba(x,y);
            }else{
                node ex=find(x);
                ll a=ex.v;
                ll b=ex.w-ex.v;
                ans=res*qpow(qpow(3,b),p-2)%p*qpow(2,a)%p*qpow(qpow(3, a),p-2)%p;
                printf("%lld\n",ans);
            }
        }
    }
}
View Code

相关文章:

  • 2021-09-06
  • 2021-11-20
  • 2021-07-11
  • 2022-01-10
  • 2022-12-23
  • 2021-12-23
  • 2022-01-21
猜你喜欢
  • 2021-12-03
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-08-08
  • 2021-04-25
相关资源
相似解决方案