P8819 [CSP-S 2022] 星战 题解

“不可以,总司令”

题目传送门

随机化的巧妙运用

考虑什么时候可以发起反攻,
每个节点都可以走到一个环上,每个节点的出度为\(1\) .....

事实上,我们会发现第一个条件是没用的,因为当每个节点出度为一时就一定可以走到一个环上

所以这个问题就转化为了判断当前的图是否每个点的出度为 \(1\)

但是我们发现如果维护每个点的出度的话复杂度会假掉,修复/炸掉一个节点是要遍历他的所有出度,不行。

既然维护出度不行,难道我们维护入度吗?

还真是,维护入度可以在 O(1) 的时间里实现

但是维护入度有一个问题,

每个节点入度为 \(1\) 仅仅只是 每个结点的出度唯一的 必要条件

那我们就要想办法将这个必要条件尽可能转化为 充要条件 ,也就是说要让每个节点给其他节点带来的入度变得特殊

所以,我们最终会想到给每个节点附上一个随机权值,看最终所有入度的权值之和是否等于每个节点出度为 \(1\) 时的入度权值之和

然后这题就做完了

上代码!

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
mt19937 rnd;
int n, m,q;
struct edge
{
    int f, t;
};
edge eds[1000010];
struct node
{
    int num;
    int key;
    vector<int> to;
    ll tin_;
    ll in_;//表示这个节点在一开始的入度之和
    // ll out_;
};
node nod[1000010];
ll tot_quan;//总的权值
ll ans_quan;//所有节点出度为 1 时的权值之和
int main()
{
    ios::sync_with_stdio(false);
    srand(time(NULL));
    rnd.seed(rand());
    cin >> n >> m;
    int a, b, c;
    for (int yy = 1; yy <= n; yy++)
    {
        nod[yy].key = rnd();//给每个点附上随机权值
        ans_quan += nod[yy].key;
    }
    for (int ww = 1; ww <= m; ww++)
    {
        cin >> a >> b;
        eds[ww].f = a;
        eds[ww].t = b;
        nod[a].to.push_back(ww);
        // nod[a].out_ += nod[a].key;
        nod[b].in_ += nod[a].key;

    }
    for (int ww = 1; ww <= n; ww++)
    {
        tot_quan += nod[ww].in_;
        nod[ww].tin_=nod[ww].in_;
    }
    cin >> q;
    int t;
    for (int ww = 1; ww <= q; ww++)//接下来模拟操作即可
    {
        cin >> t;
        if (t == 1)
        {
            cin>>a>>b;
            tot_quan-=nod[a].key;
            nod[b].tin_-=nod[a].key;
        }
        else if (t == 2)
        {
            cin>>a;
            tot_quan-=nod[a].tin_;
            nod[a].tin_=0;
        }
        else if (t == 3)
        {
            cin>>a>>b;
            tot_quan+=nod[a].key;
            nod[b].tin_+=nod[a].key;
        }
        else if (t == 4)
        {
            cin>>a;
            tot_quan+=(nod[a].in_-nod[a].tin_);
            nod[a].tin_=nod[a].in_;
        }
        if(tot_quan==ans_quan)
        {
            cout<<"YES\n";
        }
        else
        {
            cout<<"NO\n";
        }
    }

    return 0;
}
posted @ 2024-10-06 16:33  sea-and-sky  阅读(24)  评论(0编辑  收藏  举报