csp2022 T3 的条件充要性证明

必要性显然。

当且仅当只有一个从该据点出发的虫洞可用时

考虑我的暴力做法是缩点成若干 DAG,然后对强连通分量点数大于等于 2 的权值赋为 1,其他赋为 0,然后建反图跑拓扑,看看是不是每个点都能被传递到权值 1。

然后你这样做显然很复杂,根据经验,你觉得不够优美,并且猜测没有人会优化!显然是你性质/条件没找对。

考虑先判完充要后,细究我们缩点后的 DAG。

建议自己画个图。

  • 入度为 0 的点的强连通分量大小一定为 1。
    证明:考虑大于等于 1 的情况成环,那么已经满足环内每个点出度为 1 了,结果还得多一条出来,直接被必要条件判掉了。

  • 强连通分量出度为 1 \(\Leftrightarrow\) 强连通分量大小为 1
    证明:类上条结论证即可。若有出边,显然被判掉。

  • 只有出度为 0 的点的权值为 1
    证明:显然出度为 0,没被判掉,所以一定成环。

然后你想 DAG 只有出度为 0 的点权值为 1,接下来建反图,显然以这些点为源点,每个点都能跑得到。若存在孤立强连通分量的话也显然。

哈哈,你这个结论假如猜对的话,随便过 T3。

考虑条件不好做,且等价于边为 \(n\),每个点的度数为奇数。

考虑奇数想到异或,然后你随便做一下就好了。

也就是说,对于一条边 \((x,y)\),就对全局答案异或上 \(v_x\)\(v_x\) 为给 \(x\) 赋的随机权值。

#include <bits/stdc++.h>
//#define int long long
#define pb push_back
using namespace std;
const int N=(int)(5e5+5);
mt19937 RAND(time(0)^1919810); 
int n,m,d[N],v[N],f[N],sum[N],del[N],in[N];
signed main() {
	cin.tie(0); ios::sync_with_stdio(false);
	cin>>n>>m;
	int bian=m,val=0,Lim=0;
	for(int i=1;i<=n;i++) v[i]=RAND(),Lim^=v[i];
	for(int i=1;i<=m;i++) {
		int x,y; cin>>x>>y;
		++d[x]; val^=v[x]; ++in[y];
		sum[y]^=v[x];
	}
	int q; cin>>q;
	while(q--) {
		int op; cin>>op;
		if(op==1) {
			int x,y; cin>>x>>y;
			--bian; f[y]^=v[x]; val^=v[x]; ++del[y];
		} else if(op==2) {
			int x; cin>>x;
			int qwq=sum[x]^f[x]; //未 
			val^=qwq; f[x]=sum[x]; 
			int re=in[x]-del[x];
			bian-=re;
			del[x]=in[x];
		} else if(op==3) {
			int x,y; cin>>x>>y; 
			++bian; f[y]^=v[x]; val^=v[x]; --del[y];
		} else if(op==4) {
			int x; cin>>x;
			bian+=del[x];
			val^=f[x]; f[x]=0; del[x]=0;
		}
		if(val==Lim&&bian==n) cout<<"YES\n";
		else cout<<"NO\n";
	} 
	return 0;
} 

posted @ 2022-10-31 20:41  FxorG  阅读(59)  评论(0编辑  收藏  举报