P8819 [CSP-S 2022] 星战 做题记录

不可以,总司令。

题目传送门

思路

首先,当图中每个点出度为 \(1\) 时,从任一点出发必定会进入环。

证明:假设有一点不符合,则沿着它的出边一直走会到一个出度为 \(0\) 的「终点」,与每个点出度为 \(1\) 矛盾。

想通了这点,这题就不难了。

发现出度要 \(O(n)\) 维护,入度可以 \(O(1)\) 维护,考虑 Hash。

具体地,给每个点赋一个随机权值 \(w(p)\),入度为进入它的点的权值和,则大概率 \(\sum_{p \in V} w(p) = \sum p.\mathrm{in}.\mathrm{wei} \iff \sum p.\mathrm{in}= \lvert V \rvert\)

Code

#include <iostream>
#include <random>
#define UP(i,s,e) for(auto i=s; i<e; ++i)
#define DOUBLE_HASH 1
using std::cin; using std::cout;
std::mt19937 rdna(0x383494);
using ll = long long;
using ull = unsigned ll;
using i128 = __int128;
constexpr ll MOD1 = 0x383494000111CCF;
constexpr ll MOD2 = 0x383494000222CCF;
constexpr int N = 5e5;
namespace m{ // }{{{
#if DOUBLE_HASH
struct Num{
	ll val1, val2;
	Num &operator=(Num const&)=default;
	Num &operator=(ll x){ val1 = x%MOD1; val2 = x%MOD2; return *this; }
	Num(){}
	Num(ll x, ll y):val1(x%MOD1), val2(y%MOD2){}
	bool operator==(Num const b){
		return (val1-b.val1)%MOD1 == 0 && (val2-b.val2)%MOD2 == 0;
	}
	Num &operator+=(Num const b){
		val1 += b.val1;
		val1 %= MOD1;
		val2 += b.val2;
		val2 %= MOD2;
		return *this;
	}
	Num &operator-=(Num const b){
		val1 -= b.val1;
		val1 %= MOD1;
		val2 -= b.val2;
		val2 %= MOD2;
		return *this;
	}
};
#else
using Num = ull;
#endif
Num pri[N], sum[N], allsum[N]; 
// sum[i]: linked roads, allsum[i]: linked & destroyed
Num nowsum, tot; // all degs; ans when print YES
int in, im;
void work(){
	cin >> in >> im; 
	UP(i, 0, in){
#if DOUBLE_HASH
		pri[i] = {(ll)rdna(), (ll)rdna()};
#else
		pri[i] = (ll)rdna();
#endif
		tot += pri[i];
	}
	UP(i, 0, im){
		int iu, iv;
		cin >> iu >> iv; iu--, iv--;
		allsum[iv] += pri[iu];
	}
	UP(i, 0, in){
		sum[i] = allsum[i];
		nowsum += sum[i];
	}
	int iq; cin >> iq;
	UP(i, 0, iq){
		int op, iu, iv;
		cin >> op >> iu, iu--;
		if(op&1) cin >> iv, iv--;
		if(op == 1){
			sum[iv] -= pri[iu];
			nowsum -= pri[iu];
		} else if(op == 2){
			nowsum -= sum[iu];
			sum[iu] = 0;
		} else if(op == 3){
			sum[iv] += pri[iu];
			nowsum += pri[iu];
		} else {
			nowsum -= sum[iu];
			nowsum += allsum[iu];
			sum[iu] = allsum[iu];
		}
		if(nowsum == tot){
			cout << "YES\n";
		} else {
			cout << "NO\n";
		}
	}
}
} // {}}}
int main(){std::ios::sync_with_stdio(0); cin.tie(0); m::work(); return 0;}
posted @ 2023-09-02 13:22  383494  阅读(100)  评论(0编辑  收藏  举报