题解 或许

传送门

在打不开 OJ 的情况下考 OJ 上的题是一种什么样的精神体验?

发现是带删除线性基的板子题
那么 \(O(n\log n)\) 的带删除线性基(离线):
先说做法:
对线性基中每个基底维护出其删除时间 \(tim_i\)
插入一个数时,若新插入的数与某个基底线性相关且删除时间更晚则交换这个数与基底
做查询或其他操作时直接忽略掉删除时间早于当前时间的基底
正确性考虑若当前线性基中一个基底已被删除,则一定没有能代替它的数
而插入一个新数时可能造成一个已经被删除的基底被交换后继续插入,但因为其删除时间较早并无影响

然后是强制在线做法:
考虑一个基底在什么情况下不能直接删
一定是有些(最终)比它小的基底在插入时异或过它
那么对每个数维护 \(p\) 集合为其插入时异或过的数
删除时若线性基外有可以代替这个数的数则直接替换
若没有考虑消除这个基底的影响
找到最小的 p 集合包含当前要删除的数的一个基底
用这个基底去消所有的包含当前要删除的数的基底(包括其本身)
这相当于用最小的这个基底替换掉了要删除的这个基底
因为是最小的易知无后效性

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 2000010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, k, q;
set<int> s;
pair<int, int> op[N];

namespace force{
	bool vis[N];
	int dsu[N], ans;
	inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
	int query() {
		for (int i=0; i<n; ++i) dsu[i]=i;
		for (int i=0; i<n; ++i)
			for (auto it:s) dsu[find(i)]=find(i^it);
		memset(vis, 0, sizeof(vis));
		int ans=0;
		for (int i=0; i<n; ++i) if (!vis[find(i)]) ++ans, vis[find(i)]=1;
		return ans;
	}
	void solve() {
		for (int i=1; i<=q; ++i) {
			if (op[i].fir==1) s.insert(op[i].sec);
			else s.erase(op[i].sec);
			ans^=query();
		}
		printf("%d\n", ans);
	}
}

namespace task1{
	int ans[N];
	map<int, int> mp;
	#define M 200010
	int tl[M<<2], tr[M<<2];
	vector<int> add[M<<2];
	#define tl(p) tl[p]
	#define tr(p) tr[p]
	struct basic{
		int base[32], siz;
		basic(){memset(base, 0, sizeof(base)); siz=0;}
		inline void ins(int t) {
			for (int i=30; ~i; --i) if (t&(1<<i)) {
				if (!base[i]) {base[i]=t; ++siz; return ;}
				else t^=base[i];
			}
		}
	}dat[M<<2];
	void build(int p, int l, int r) {
		tl(p)=l; tr(p)=r;
		if (l==r) return ;
		int mid=(l+r)>>1;
		build(p<<1, l, mid);
		build(p<<1|1, mid+1, r);
	}
	void upd(int p, int l, int r, int val) {
		// cout<<"upd: "<<l<<' '<<r<<' '<<val<<endl;
		if (l<=tl(p)&&r>=tr(p)) {add[p].pb(val); return ;}
		int mid=(tl(p)+tr(p))>>1;
		if (l<=mid) upd(p<<1, l, r, val);
		if (r>mid) upd(p<<1|1, l, r, val);
	}
	void query(int p, basic tem) {
		for (auto& it:add[p]) tem.ins(it); //, cout<<"ins: "<<it<<endl;
		if (tl(p)==tr(p)) {/* cout<<"siz: "<<tem.siz<<endl; */ ans[tl(p)]=1<<(k-tem.siz); return ;}
		query(p<<1, tem); query(p<<1|1, tem);
	}
	void solve() {
		// cout<<double(sizeof(dat))/1000/1000<<endl;
		build(1, 1, q);
		for (int i=1; i<=q; ++i) {
			if (op[i].fir==1) mp[op[i].sec]=i;
			else upd(1, mp[op[i].sec], i-1, op[i].sec), mp.erase(op[i].sec);
		}
		for (auto it:mp) upd(1, it.sec, q, it.fir);
		query(1, basic());
		int sum=0;
		for (int i=1; i<=q; ++i) sum^=ans[i];
		// cout<<"ans: "; for (int i=1; i<=q; ++i) cout<<ans[i]<<' '; cout<<endl;
		printf("%d\n", sum);
	}
}

namespace task2{
	int ans;
	struct basic{
		int base[31], siz;
		basic(){memset(base, 0, sizeof(base)); siz=0;}
		inline void ins(int t) {
			for (int i=30; ~i; --i) if (t&(1<<i)) {
				if (!base[i]) {base[i]=t; ++siz; return ;}
				else t^=base[i];
			}
		}
	}t;	
	void solve() {
		for (int i=1; i<=q; ++i) {
			if (op[i].fir==1) t.ins(op[i].sec);
			ans^=1<<(k-t.siz);
		}
		printf("%d\n", ans);
	}
}

namespace task{
	int lst[N], ans;
	unordered_map<int, int> mp;
	struct basic{
		int base[31], tim[31];
		basic(){memset(base, 0, sizeof(base));}
		inline void ins(int val, int del) {
			for (int i=30; ~i; --i) if (val&(1<<i)) {
				if (!base[i]) {base[i]=val; tim[i]=del; return ;}
				if (del>tim[i]) swap(base[i], val), swap(tim[i], del);
				val^=base[i];
			}
		}
		int qsiz(int now) {
			int ans=0;
			for (int i=30; ~i; --i) if (tim[i]>=now) ++ans;
			return ans;
		}
	}t;	
	void solve() {
		for (int i=1; i<=q; ++i) {
			if (op[i].fir==1) mp[op[i].sec]=i;
			else lst[mp[op[i].sec]]=i-1, mp.erase(op[i].sec);
		}
		for (auto it:mp) lst[it.sec]=q;
		for (int i=1; i<=q; ++i) {
			t.ins(op[i].sec, lst[i]);
			ans^=1<<(k-t.qsiz(i));
		}
		cout<<ans<<endl;
	}
}

signed main()
{
	freopen("A.in", "r", stdin);
	freopen("A.out", "w", stdout);

	n=1<<(k=read()); q=read();
	if (!q) {puts("0"); return 0;}
	for (int i=1,u,x; i<=q; ++i) {
		u=read(); x=read();
		op[i]={u, x};
	}
	// force::solve();
	// if (q<=100000) task1::solve();
	// else task2::solve();
	task::solve();

	return 0;
}
posted @ 2022-04-10 16:15  Administrator-09  阅读(3)  评论(0编辑  收藏  举报