这道题我用类似并查集的方法求出每一个点追溯到的祖先和是否改变了祖先的逻辑值,再用染色法判断有没有矛盾
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
#define ROF(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int N=3e5+40,T=3e5+10,F=3e5+20,U=3e5+30;
int fa[N],ww[N],n,m,visp[N],vis[N];
struct node{
int to,nxt;int w;
}edge[N<<1];
int head[N],tot;
void add(int x,int y,int z) {
edge[++tot].to=y;edge[tot].w=z;edge[tot].nxt=head[x];head[x]=tot;
}
void INIT() {
tot=1;
memset(head,0,sizeof(head));
memset(vis,-1,sizeof(vis));
memset(visp,0,sizeof(visp));
FOR(i,1,N-1)fa[i]=i,ww[i]=0;
}
int dfs_c(int x) {//统计 U 的数量
visp[x]=1;int ret=((x!=T)&&(x!=F)&&(x!=U));
for(int i=head[x];i;i=edge[i].nxt){
int v=edge[i].to;if(visp[v])continue;
ret+=dfs_c(v);
}
return ret;
}
int dfs(int x,int fa,int val) {
if(vis[x]==-1) {
vis[x]=val;
} else {
if(vis[x]!=val)return true;
return false;
}
for(int i=head[x];i;i=edge[i].nxt) {
if(i==fa)continue;
int v=edge[i].to,w=edge[i].w;
if(dfs(v,i^1,val^w))return true;
}
return false;
}
int main(){
// freopen("P9869_1.in","r",stdin);
// freopen("tribool.out","w",stdout);
int c,T;scanf("%d%d",&c,&T);
while(T--) {
scanf("%d%d",&n,&m);
INIT();
FOR(i,1,m) {
char op[5];int x,y;
scanf("%s%d",op,&x);int nm=op[0];
if(nm=='+'||nm=='-') {
scanf("%d",&y);
if(nm=='+'){
fa[x]=fa[y];ww[x]=ww[y];
} else if(nm=='-') {
fa[x]=fa[y];ww[x]=ww[y]^1;
}
}
else {
ww[x]=0;
if(nm=='T')fa[x]=T;
if(nm=='F')fa[x]=F;
if(nm=='U')fa[x]=U;
}
}
FOR(i,1,n){
add(i,fa[i],ww[i]);
add(fa[i],i,ww[i]);
}
int cnt=dfs_c(U);//visp是标U的
FOR(i,1,n) {
if(vis[i]==-1&&!visp[i]) {
if(dfs(i,0,0)) {//产生矛盾
cnt+=dfs_c(i);
}
}
}
printf("%d\n",cnt);
}
// fclose(stdin);
// fclose(stdout);
return 0;
}
但是在测试点 1 的最后两个数据中,选择不同的数据数量 T 会得到不同的结果
比如
1 2
10 10
+ 5 3
+ 4 3
U 3
- 1 7
- 2 9
+ 7 2
U 9
T 6
- 10 10
- 8 8
10 10
+ 9 8
- 8 2
+ 2 9
- 1 3
+ 3 4
+ 4 5
+ 5 6
- 6 7
- 7 10
+ 10 1
当数据总数 T 是 1 的时候,第一组数据输出的是正确答案 9 而当 T 是 2 时第一组数据输出的是错误答案 10