zoukankan      html  css  js  c++  java
  • CCPC-Wannafly Winter Camp Day3 (Div2, onsite) I 石头剪刀布(按秩合并并查集)

    题解:每次有两个事件:

    1. y

    y去挑战xx,如果赢了可以坐在x

     

    • x的位置,打平或者输了就要被淘汰。
    • 询问在进行所有一类事件后,有多少种情况可以让x
    1. x现在还没有被淘汰。

    对于第二类事件,我们假设x

    x挑战了别人aa次,被挑战了bb次,那他没有被淘汰的概率就是3n(13)a(23)b3n(31)a(32)b。因此我们只要知道a,ba,b的值就可以知道答案。因此我们需要维护a,ba,b的值。对于第一类事件,我们画画图就会发现它会形成树状关系。那么我们就可以维护这颗树的节点信息,然后去询问就好了。很容易想到并查集了,但是这里似乎并不能直接用路径压缩,原因听一位巨巨说因为每个节点都有权值,根节点也有权值,每次查询的时候会重复累加根节点的信息,所以需要按秩合并。我们可以维护两个信息:每个人的总比赛场次,主场比赛场次。对于yy挑战xx,那么肯定y,xy,x的总比赛场次都加11,xx主场比赛场次加11。那么,对于集合yy合并到集合xx,会将xx设为yy的父亲,因为每个节点都包含着它当前这个集合的增量信息,也就意味着集合yy里的增量会凭空多增加xx的增量。因此合并的时候需要减去。然后findfind的时候累加增量即可。

    这个题从概率的方向去考虑方案数

    用并查集来维护之间的战斗关系,同时记录客场作战次数和主场作战次数

    两个集合合并的的时候要减去fa的信息,




     1 #include<bits/stdc++.h>
     2 typedef long long LL;
     3 using namespace std;
     4 const int N = 2E5+10, mod = 998244353;
     5 LL w[N],v[N],rk[N],f[N];
     6 struct node
     7 {
     8     int fa;
     9     LL _w,_v;
    10 };
    11 LL _pow(LL a,LL n)
    12 {
    13     LL ret = 1;
    14     while(n)
    15     {
    16         if(n & 1) ret = a * ret % mod;
    17         a = a * a % mod;
    18         n >>= 1;
    19     }
    20     return ret;
    21 }
    22 LL Inv(LL n)
    23 {
    24     return _pow(n, mod - 2);
    25 }
    26 node _find(int x)
    27 {
    28     if(x == f[x]) return node{x,w[x],v[x]};
    29     node t = _find(f[x]);
    30     return node{t.fa, t._w + w[x], t._v + v[x]};
    31 }
    32 void _merge(int x,int y)
    33 {
    34     int t1 = _find(x).fa;
    35     int t2 = _find(y).fa;
    36     if(t1 != t2)
    37     {
    38         w[t1]++;
    39         v[t1]++;
    40         w[t2]++;
    41         if(rk[t1] >= rk[t2])
    42         {
    43             w[t2] -= w[t1];
    44             v[t2] -= v[t1];
    45             f[t2] = t1;
    46             rk[t1]++;
    47         }
    48         else
    49         {
    50             w[t1] -= w[t2];
    51             v[t1] -= v[t2];
    52             f[t1] = t2;
    53             rk[t2]++;
    54         }
    55     }
    56 }
    57 int main()
    58 {
    59 
    60     for(int i = 0; i < N; ++i)
    61     {
    62         f[i] = i;
    63     }
    64     int n,m,c,x,y;
    65     cin >> n >> m;
    66     LL t = _pow(3,n);
    67     for(int i = 0; i < m; ++i)
    68     {
    69         scanf("%d",&c);
    70         if(c == 1)
    71         {
    72             scanf("%d %d",&x,&y);
    73             _merge(x,y);
    74         }
    75         else
    76         {
    77             scanf("%d",&x);
    78             node t1 = _find(x);
    79             LL a = t1._v, b = t1._w - t1._v;
    80             LL ans = t * Inv(_pow(3,b)) % mod * _pow(2,a) % mod * Inv(_pow(3,a)) % mod;
    81             printf("%lld
    ",ans);
    82         }
    83     }
    84     return 0;
    85 }

  • 相关阅读:
    关于UITapGestureRecognizer的一些问题
    自定义导航栏返回按钮
    mousewheel滚轮事件 浏览器的写法
    Apache日志不记录图片文件设置方法和来源日志的配置
    redis持久化配置
    haproxy实现负载均衡
    Keepalived高可用软件的安装与配置
    Sublime text2用户自定义配置
    判断各版本的最简写法
    Ubuntu防火墙 UFW 设置
  • 原文地址:https://www.cnblogs.com/zhangbuang/p/10878120.html
Copyright © 2011-2022 走看看