大家好啊,我是唐诗

洛谷 P9869 [NOIP2023] 三值逻辑

首先看到这题,我们就可以拿 \(20\) 分的暴力。

然后对于仅有 \(T、F、U\) 的测试点,同一个位置取最后赋值的值即可,未赋值的一律是 T,这样就有有了 \(20\) 分。

考虑只有 \(U、+\) 的测试点,维护每个节点实际上最终被哪个节点赋值了(路径压缩),然后对于值被赋成同样位置的节点的值的点,它们的值都是一样的。也就是说,这其中一个集合,只要有一个被赋值为 U 那么其他的也绝对是 U,具体样子是一棵树,并查集维护即可,\(O(n)\),也是 \(20\) 分。

接下来,考虑正解。

首先需要知道,题目中要求我们的操作前与操作后值一致究竟意味着什么,不然,如果单纯这样维护,是困难的。由于每一个元素的值只会被改为最后一个修改它值的值,所以,我们只要将初值赋为最后一个修改它值的值即可,但是有一种情况,修改它的值实际上是由它自己决定的,会更随它的初值改变,这样的话就没办法了,只能让它为不确定。

于是我们考虑画出影响图,即对于形如 \(+、-\) 操作时,连一个从 \(y\)\(x\) 的边,意味着它受 \(y\) 的影响。于是最后确定答案即为对于这样的森林,有多少节点被改为了自己值的非值或者被赋值为 \(U\) 的影响树的大小和。

对于 \(+\) 我们 \(+\) 很好操作,但对于 \(-\) 呢,毕竟需要把值非了,所以考虑建一个点表示非那个点,然后对于所有非点建一个非图。所以我们需要考虑一个点是否能通过边到达非它的值,如果可以,那这棵树就全不知道了(全是 \(U\))。

考虑赋值,我们只需要建三个虚点表示 \(T、F、U\) 即可,然后操作如上。

思路可能比较难懂,实际上我们是用反图上的点,表示 \(-\) 这种情况,然后反点不可能就没有被它赋值或被它赋值为它的反的情况,所以就在反图上也要正常连边,考虑所有情况。你实际情况下关系是有两种的:赋值为它的值,赋值为它的相反值。那么这两种操作,赋的值的来源点对于那个点值的来源点有两种情况:不变,反。所以对于目前点的连边,也是要考虑对于赋的值的来源点对于那个点值的来源点的正负关系。然后,有一些情况一个点是 \(U\)

1.可以到达自己的反值点。

2.被赋值 \(U\)

3.目前逻辑树内有 \(U\) 点。

处理即可,考虑反点和虚点的问题:对于反点,给目前点的负数,对于虚点 \(T=10^5+1,F=-10^5-1,U=0\),个人认为这样的处理是精妙的。

Code

//#include <bits/stdc++.h>
//using namespace std;
//const int N=5e5+5;
//int p[N],value[N],another[N],sz[N];
//bool dead[N],used[N];
//struct qry {
//	char opt;
//	int x,y;
//}qrys[N];
//int find(int x) {
//	if(p[x]!=x) return p[x]=find(p[x]);
//	return x;
//}
//int orzero(char x) {
//	if(x=='T') return 1;
//	else if(x=='F') return 2;
//	else if(x=='U') return 3;
//}
//int n,m;
//signed main() {
//	int c,tt;
//	cin>>c>>tt;
//	while(tt--) {
//		cin>>n>>m;
//		for(int i=1;i<=m;i++) {
//			cin>>qrys[i].opt;
//			if(qrys[i].opt=='+'||qrys[i].opt=='-') cin>>qrys[i].x>>qrys[i].y;
//			else cin>>qrys[i].x;
//		}
//		reverse(qrys+1,qrys+1+n);
////		for(int i=1;i<=m;i++) {
////			if(qrys[i].opt=='+'||qrys[i].opt=='-') cout<<qrys[i].opt<<' '<<qrys[i].x<<' '<<qrys[i].y<<endl;
////			else cout<<qrys[i].opt<<' '<<qrys[i].x<<endl;
////		}
//		for(int i=1;i<=n;i++)
//			p[i]=i,used[i]=0,dead[i]=0,value[i]=0,another[i]=0,sz[i]=1;
//		for(int i=1;i<=m;i++) {
//			if(used[qrys[i].x]) continue;
//			if(qrys[i].y!=qrys[i].x) used[qrys[i].x]=1;
//			if(qrys[i].opt!='+'&&qrys[i].opt!='-')
//				value[find(i)]=orzero(qrys[i].opt);
//			else {
//				if(qrys[i].opt=='+') {
//					int fx=find(qrys[i].x),fy=find(qrys[i].y);
//					if(value[fx]==0) {
//						p[fx]=fy;
//						sz[fy]+=sz[fx];
//					}
//					else if(value[fy]==0) {
//						p[fy]=fx;
//						sz[fx]+=sz[fy];
//					}
//					else if(value[fx]==value[fy]) {
//						p[fx]=fy;
//						sz[fy]+=sz[fx];
//					} 
//					else {
//						
//					}
//				}
//				else {
//					int fx=find(qrys[i].x),fy=find(qrys[i].y);
//					
//				}
//			}
//		}
//		memset(used,0,sizeof used);
//		int ans=0;
//		for(int i=1;i<=m;i++) {
//			if(used[find(i)]&&value[find(i)]==orzero('U')) {
//				ans+=sz[find(i)];
//				used[find(i)]=1;
//			}
//		}
//		cout<<ans<<endl;
//	} 
//	return 0;
//} 

//我用草饲养你的马
//明明想的关键做法对了啊! 
#include <bits/stdc++.h>
#define int long long
#define T 100001
#define F -100001
#define U 0
using namespace std;
const int N=5e5+5;
unordered_map<int,int> p;
unordered_map<int,bool> vis;
int n,m,tt,c,x,y;
int ans=0;
int find(int x) {
	if(p[x]!=x) return p[x]=find(p[x]);
	return x;
}
int check(int x) {
	//cout<<"?"<<x<<' '<<vis[-x]<<endl;
	if(x==T||x==F) return x;
	if(x==U||vis[-x]) {
		//cout<<"**"<<endl;
		return U;
	}
	int go;
	if(vis[x]) return x;
	if(x==p[x]) return x;
	else {
		vis[x]=1;
		go=p[x]=check(p[x]);
		//cout<<x<<' '<<p[x]<<"(("<<endl;
		vis[x]=0;
	}
	return go;
}
signed main() {
	cin>>c>>tt;
	while(tt--) {
		cin>>n>>m;
		for(int i=1;i<=n;i++) p[i]=i,p[-i]=-i;
		for(int i=1;i<=m;i++) {
			char opt;
			cin>>opt;
			if(opt=='+'||opt=='-') {
				cin>>x>>y;
				if(opt=='+') p[x]=p[y],p[-x]=p[-y];
				else p[x]=p[-y],p[-x]=p[y];
			}
			else {
				cin>>x;
				if(opt=='T') p[x]=T,p[-x]=F; 
				else if(opt=='F') p[x]=F,p[-x]=T;
				else p[x]=U,p[-x]=U;
			}
		}
		ans=0;
		for(int i=1;i<=n;i++) {
			//cout<<"!!"<<i<<endl;
			if(check(i)==U) ans++;
		}
		cout<<ans<<endl;
	}
	return 0;
} 
posted @ 2024-08-28 21:09  PM_pro  阅读(28)  评论(0)    收藏  举报