CF1217F

发布时间 2023-12-23 20:50:33作者: yinhee

强制在线是诈骗,还是很有意思的。

首先,如果没有强制在线就是一个 SGT 分治板子。强制在线看起来做不了,但是发现 \(lastans=0/1\)。这启示我们不同的加边可能性不会太多。考虑先记录两种加边可能。

容易发现,如果当前时刻 \(j\) 可能操作 \((u,v)\),上一次可能的时刻是 \(i\),则 \([i,j)\) 时间内该边的状态都是一定不会变化的。反之可能变化,所以设 \((u,v)\) 可能出现的时刻是 \(i_1,i_2,i_3,\cdots,i_k\),则在线段树上对 \([i_1,i_2),[i_2,i_3),\cdots,[i_{k-1},i_k),[i_k,m]\) 进行区间插入一个加入 \((u,v)\) 的操作。

现在就要考虑怎么判断某条边是否被操作,发现这由进行加边操作前的某一次询问决定,而线段树分治最后处理答案刚好是满足在时间轴上从前往后进行的,所以可以在每次递归到叶子时分两种情况:

  • 该时间进行了加/删边操作。

此时已经知道 \(lastans\),所以可以知道实际操作的是哪一条边,直接将这条边的存在状态取反即可。用 map 维护。

  • 查询。

求出实际查询的两点之后查询答案,记录新的 \(lastans\)

每次在某个节点上面有加边操作就判断当前边是否存在,然后操作即可。

一个小细节是 \([l,r)\) 区间的 \((u,v)\) 加边是否进行取决于在 \(l\) 代表的叶子节点操作后,边 \((u,v)\) 的状态,则先要求出 \(l\) 的答案才能决定 \((u,v)\) 加边不加。此时可以将 \([l,r)\) 变成 \((l,r)\),因为 \(l\) 位置一定不是查询,所以是不影响的。

code:

点击查看代码
int n,m,top,st[N];
pii a[N];
bool lans,pd[N],ans[N];
map<pii,int> lst,vis;
mt19937 rnd(time(0));
struct SGT{
	int tot,head[N<<2];
	struct node{pii x;int nxt;}e[N<<5];
	il void add(int o,pii k){e[++tot]={k,head[o]},head[o]=tot;}
	struct BCJ{
		int fa[N],c[N];
		void init(){rep(i,1,n)c[i]=rnd(),fa[i]=i;}
		int find(int x){return fa[x]==x?x:find(fa[x]);}
		il void merge(int x,int y){
			x=find(x),y=find(y);
			if(c[x]>c[y])swap(x,y);
			fa[x]=y,st[++top]=x;
		}
		il void del(int x){while(top>x)fa[st[top]]=st[top],top--;}
	}S;
	void update(int l,int r,int o,int x,int y,pii k){
		if(x>y)return;
		if(l>=x&&r<=y)return add(o,k);
		int mid=(l+r)>>1;
		if(x<=mid)update(l,mid,o<<1,x,y,k);
		if(y>mid)update(mid+1,r,o<<1|1,x,y,k);
	}
	void solve(int l,int r,int o){
		int npos=top;
		go(i,o){
			pii x=e[i].x;
			if(vis[x])S.merge(x.fi,x.se);
		}
		if(l==r){
			int u=a[l].fi,v=a[l].se;
			if(lans)u=u%n+1,v=v%n+1;
			if(u>v)swap(u,v);
			if(pd[l]){
				if(S.find(u)==S.find(v))ans[l]=lans=1;
				else ans[l]=lans=0;
			}else vis[Mp(u,v)]^=1;
			return S.del(npos);
		}
		int mid=(l+r)>>1;
		solve(l,mid,o<<1),solve(mid+1,r,o<<1|1);
		S.del(npos);
	}
}T;
void Yorushika(){
	scanf("%d%d",&n,&m);
	rep(i,1,m){
		int op,u,v;scanf("%d%d%d",&op,&u,&v);
		if(u>v)swap(u,v);
		a[i]=Mp(u,v);
		if(op==1){
			if(lst[Mp(u,v)])T.update(1,m,1,lst[Mp(u,v)]+1,i-1,Mp(u,v));
			lst[Mp(u,v)]=i;
			u=u%n+1,v=v%n+1;
			if(u>v)swap(u,v);
			if(lst[Mp(u,v)])T.update(1,m,1,lst[Mp(u,v)]+1,i-1,Mp(u,v));
			lst[Mp(u,v)]=i;
		}else pd[i]=1;
	}
	for(auto i:lst)T.update(1,m,1,i.se+1,m,i.fi);
	T.S.init(),T.solve(1,m,1);
	rep(i,1,m)if(pd[i])pc(ans[i]+'0');
}
signed main(){
	int t=1;
	//	scanf("%d",&t);
	while(t--)
		Yorushika();
}