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;
}
}

浙公网安备 33010602011771号