列表

详情


NC248254. 琉焰

描述

云浅有一张 n 个节点的图 ,一开始图中没有边,即
现在有 m 次操作,每次操作她会给出一条边 (u,v),若此时 ,则从 E 中删除 (u,v);否则向 E 中加入 (u,v)。在每次操作后,你需要输出:有多少个生成子图 满足 H 中每个点的度数均为偶数。
答案对 998244353 取模。
生成子图的定义是:对于图 ,若图 满足 ,则称 HG 的生成子图。

输入描述

第一行两个正整数 n,m
接下来 m 行,每行两个正整数 u,v,表示一次操作。
对于 的数据,保证

输出描述

输出 m 行,第 i 行表示在前 i 次操作后,符合条件的生成子图 H 的个数。

示例1

输入:

6 9
1 2
2 5
1 4
1 5
4 5
1 4
2 3
3 5
1 5

输出:

0
0
0
1
3
1
1
3
1

说明:

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++ 11.0.1) 解法, 执行用时: 561ms, 内存消耗: 57520K, 提交时间: 2023-02-16 20:14:40

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+5;
const int mod=998244353;

struct dsu {
	int fa[N],siz[N],st[N],top;
	void send(int n) {
		for (int i=1;i<=n;i++) {
			fa[i]=i,siz[i]=1;
		}
	}
	int find(int x) {
		return fa[x]==x?x:find(fa[x]);
	}
	void merge(int u,int v) {
		int x=find(u),y=find(v);
		if (x==y) {
			return;
		}
		if (siz[x]>siz[y]) swap(x,y);
		fa[x]=y;
		siz[y]+=siz[x];
		st[++top]=x;
	}
	void roll_back(int x) {
		while (top>x) {
			int now=st[top--];
			siz[fa[now]]-=siz[now];
			fa[now]=now;
		}
	}
}d;
int n,m,ans[N],pw[N];
struct segment_tree {
	#define ls (w<<1)
	#define rs (w<<1|1)
	#define mid ((l+r)>>1)
	vector<pair<int,int>>t[N*4];
	void add(int w,int l,int r,int ql,int qr,pair<int,int>x) {
		if (ql<=l&&r<=qr) {
			t[w].emplace_back(x);
			return;
		}
		if (ql<=mid){
			add(ls,l,mid,ql,qr,x);
		}
		if (qr>mid) {
			add(rs,mid+1,r,ql,qr,x);
		}
	}
	void dfs(int w,int l,int r) {
		int tmp=d.top;
		for (auto [u,v]:t[w]) {
			d.merge(u,v);
		}
		if (l==r) {
			ans[l]-=d.top;
		} else {
			dfs(ls,l,mid);
			dfs(rs,mid+1,r);
		}
		d.roll_back(tmp);
	}
	#undef mid
	#undef rs
	#undef ls
}t;
void work() {
	cin>>n>>m;
	map<pair<int,int>,int>mp;
	for (int i=pw[0]=1;i<=m;i++) {
		pw[i]=pw[i-1]*2%mod;
		int u,v;
		cin>>u>>v;
		if (mp.count({u,v})) {
			t.add(1,1,m,mp[{u,v}],i-1,{u,v});
			mp.erase({u,v});
		} else {
			mp[{u,v}]=i;
		}
		ans[i]=mp.size();
	}
	for (auto [a,b]:mp) {
		t.add(1,1,m,b,m,a);
	}
	d.send(n);
	t.dfs(1,1,m);
	for (int i=1;i<=m;i++) {
		cout<<pw[ans[i]]-1<<"\n";
	}
}

signed main() {
	ios::sync_with_stdio(false),cin.tie(0);
	cout.precision(10),cout.setf(ios::fixed);
	
	int T=1;
	while (T--) {
		work();
	} 
	
	return 0;
}

C++(g++ 7.5.0) 解法, 执行用时: 590ms, 内存消耗: 57648K, 提交时间: 2023-06-23 03:47:11

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
using namespace std;
typedef long long ll;
const int maxn=2e5,N=maxn+10,mod=998244353;
typedef pair<int,int> P;
map<P,int> last;
vector<P>dat[4*N];
int n,m,cnt,par[N],sz[N];
P a;
int tot,ans[N],two[N];
int find(int x){
	return par[x]==x?x:find(par[x]);
}
bool merge(int x,int y,stack<P> &q){
	x=find(x),y=find(y);
	if(x==y)return 1;
	if(sz[x]<sz[y])swap(x,y);
	q.push(P(x,y));
	sz[x]+=sz[y];
	par[y]=x;
    return 0;
}
void undo(stack<P> &q){
	while(!q.empty()){
		int x=q.top().fi;
		int y=q.top().se;
		q.pop();
		sz[x]-=sz[y];
		par[y]=y;
	} 
} 
void update(int p,int l,int r,int ql,int qr,P v){
	if(ql<=l&&r<=qr){
		dat[p].pb(v);
		return;
	}
	int mid=(l+r)/2;
	if(ql<=mid)update(lson,ql,qr,v);
	if(qr>mid)update(rson,ql,qr,v);
}
void dfs(int p,int l,int r){
	stack<P>q;
    int cnt=0;
	for(auto v:dat[p])
	cnt+=merge(v.fi,v.se,q); // 非树边的数量的变更
	tot+=cnt;
    if(l==r)ans[l]=two[tot]-1;
	else{
		int mid=(l+r)/2;
		dfs(lson);
		dfs(rson);
	}
	undo(q);
    tot-=cnt;
}
int main(){
	scanf("%d%d",&n,&m);
    two[0]=1;
	for(int i=1;i<=m;++i){
        two[i]=two[i-1]*2%mod;
		scanf("%d%d",&a.fi,&a.se);
		if(last.count(a)){
			update(1,1,m,last[a],i-1,a);
			last.erase(a); 
		}
		else last[a]=i;
	}
	for(auto v:last) 
	update(1,1,m,v.se,m,v.fi);
	for(int i=1;i<=m;++i)
	par[i]=i,sz[i]=1;
	dfs(1,1,m);
	for(int i=1;i<=m;++i)
	printf("%d\n",ans[i]);
	return 0;
}

上一题