loading

P12705 呃呃

题意

给你一张无向图,\(q\) 次翻转一条边的存在状态,然后查询图的四元环的存在性。

\(n,q\le 10^4\)

分析

首先有一个显然的三次方做法:维护 \(c_{x,y}\) 表示同时与 \(x,y\) 有连边的点的个数,显然存在四元环的充要条件是存在 \(c_{x,y}\ge 2\)。单次删边/加边显然可以通过 \(O(n)\) 枚举 \(i\) 来修改 \(c_{x,i}\)\(c_{y,i}\),初始枚举 \(x,y,z\) 然后 check。

发现上述做法的瓶颈在于初始的 \(c_{i,j}\) 的求值。考虑到我们只关心四元环的存在性,并且在边数过多的情况下四元环很容易存在,我们考虑先枚举 \(i\)\(i\) 的两条出边 \(j,k\),并将 \(c_{j,k}\) 加 1。正常情况下,对所有 \(i\) 做一遍是三次方的,但我们在找到一个四元环后,就停止往后枚举,修改时我们也只修改 \(i\) 之前的贡献。有一个性质是,若 \(\sum \binom{deg_i}{2}\ge \binom{n}{2}\),那么一定存在四元环。证明考虑如果不存在四元环,那么每一对 \(i,j\) 都至多有一个点使得两个点都与它有边,这说明了 \(\sum \binom{deg_i}{2}\) 的上界就是 \(i,j\) 的对数即 \(\binom{n}{2}\)。这告诉我们,如果不存在四元环,那么至多会枚举 \(\binom{n}{2}=O(n^2)\) 次,所以这个做法复杂度可以保证。具体复杂度不会证,可以感性理解。

总时间复杂度 \(O((n+q)n)\)

还有个比较有启发性的做法,我们可以考虑离线,将从来没被删过的边单独拿出来,看看有没有四元环,如果有那么全输出 Yes 即可,如果没有,上面的结论证明的这个东西的复杂度是 \(O(n^2)\) 的,然后把初始的边都加上去即可,由于只会修改 \(O(q)\) 条边,所以重新加上去的边也是 \(O(q)\) 级别的,配合 \(O(n)\) 修改总时间复杂度和上面的在线做法一样。

int n,Q;
bool a[maxn][maxn];
char s[maxn];
int cnt;
vector<int>G;
int c[maxn][maxn];
void renew(int x){
	G.clear();
	rep(i,1,n)if(a[x][i])G.pb(i);
	rep(i,0,(int)G.size()-1)rep(j,i+1,(int)G.size()-1){
		int u=G[i],v=G[j];
		c[u][v]++,c[v][u]++;
		if(c[u][v]==2)++cnt;
	}
}
void del(int x,int y){
	rep(i,1,n)if(i!=x&&i!=y){
		if(a[y][i]){
			c[x][i]--,c[i][x]--;
			if(c[x][i]==1)--cnt;
		}
	}
}
void add(int x,int y){
	rep(i,1,n)if(i!=x&&i!=y){
		if(a[y][i]){
			c[x][i]++,c[i][x]++;
			if(c[x][i]==2)++cnt;
		}
	}
}
inline void solve_the_problem(){
	n=rd(),Q=rd();
	for(int i=1;i<=n;i++){
		scanf("%s",s);
		for(int j=0;j<n;j++)
			a[i][j+1]=((s[j>>2]-'0')>>(j&3))&1;
	}
	int p=0;
	while(Q--){
		int x=rd(),y=rd();
		a[x][y]^=1,a[y][x]^=1;
		if(a[x][y]){
			if(x<=p)add(y,x);
			if(y<=p)add(x,y);
		}else{
			if(x<=p)del(y,x);
			if(y<=p)del(x,y);
		}
		if(cnt){PY;continue;}
		while(p<n&&!cnt)renew(++p);
		cnt?PY:PN;
	}
}
posted @ 2025-08-25 22:12  dcytrl  阅读(20)  评论(1)    收藏  举报