【CSP-S2022】星战 题解

随机化的题都是好题。

考场遇上随机化是真的搞心态,何况正解是用随机化通过的题本蒻至今也只在考场上遇见过两道。。。

闲言少叙,书归正传。


题目是在初始时给定一张图,然后在图上进行下列四种操作:

  • u , v u,v u,v 之间的边断开
  • u , v u,v u,v 之间的边重连
  • v v v 的所有入边断开
  • v v v 的所有入边重连

并且保证断开和重连的总是原图中的边,每次操作后询问是否满足:

  • 所有点的出度均为 1 1 1
  • 所有边都能通往或属于一个环

仔细思考,会发现其实当第一个条件满足时,第二个条件会自动满足。那么我们判断是否有:所有点的出度均为 1 1 1,即可。

考虑当所有点的出度均为 1 1 1 时,整张图的出度和为 n n n,所以判断出度和是否为 n n n 即可。但是这么做会出现问题,即 n = a + b = ( a + 1 ) + ( b − 1 ) n=a+b=(a+1)+(b-1) n=a+b=(a+1)+(b1)

解决方案也很简单,我们给每个点一个尽可能不相同的权值 w i w_i wi,然后检查每个点的出度与其权值乘积的和是否等于 ∑ i = 1 n w i \sum_{i=1}^nw_i i=1nwi 即可。这实际上相当于 Hash,权值可以直接用随机数指定(亲测令 w i = i + 1 w_i=i+1 wi=i+1 也能通过)。

这里给出一个用随机数的代码,时间复杂度 Θ ( n + m + q ) \Theta(n+m+q) Θ(n+m+q)

#include<bits/stdc++.h>
using namespace std;
//星战

const int maxn = (int)5e5 + 5;
long long allin[maxn];
long long inv[maxn];
long long tot, YES;
int w[maxn];
int n, m, q;

int main() {
    srand(time(0));
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) w[i] = rand();
    for (int i = 1; i <= n; i++) YES += w[i];
    for (int i = 1; i <= m; i++) {
        int u, v;
        scanf("%d %d", &u, &v);
        allin[v] += w[u];
        tot += w[u];
    }
    for (int i = 1; i <= n; i++) inv[i] = allin[i];

    scanf("%d", &q);
    for (int i = 1; i <= q; i++) {
        int t, u, v;
        scanf("%d", &t);
        if (t == 1) {
            scanf("%d %d", &u, &v);
            inv[v] -= w[u];
            tot -= w[u];
        }
        if (t == 2) {
            scanf("%d", &v);
            tot -= inv[v];
            inv[v] = 0;
        }
        if (t == 3) {
            scanf("%d %d", &u, &v);
            inv[v] += w[u];
            tot += w[u];
        }
        if (t == 4) {
            scanf("%d", &v);
            tot -= inv[v];
            tot += allin[v];
            inv[v] = allin[v];
        }
        if (tot == YES) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值