把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu 5385 [Cnoi2019]须臾幻境

题面传送门
自环太坑了。
首先如果离线那么显然回滚莫队+并查集就可以愉快地通过了。
但是这个是强制在线的。所以考虑换一种做法。
可以发现联通块个数就是点数减去有用的边数。
我们可以看看对于每个点,从哪个点开始可以被计算入边数。
这个可以用LCT维护时间最大生成树来搞。
然后因为强制在线。所以可以用主席树来二维数点,否则离线掉树状数组即可。
时间复杂度\(O(nlogn)\)大常数。
code:

#include<cstdio>
#include<bits/stdc++.h>
#define I inline
#define l(x) f[x].l
#define r(x) f[x].r
#define N 100039
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,op,x[N*2],y[2*N],lastans,d[N*2],root[N*2],cnt,a,b,un,wn,now;
struct tree{int l,r,f;}f[N*100];
I void get(int x,int &now,int l=0,int r=m+1){
	f[++cnt]=f[now];now=cnt;f[now].f++;if(l==r)return;int m=l+r>>1;
	(x<=m)?get(x,l(now),l,m):get(x,r(now),m+1,r);
}
I int find(int x,int y,int now,int l=0,int r=m+1){
	if(!now) return 0;if(x<=l&&r<=y) return f[now].f;int m=l+r>>1,ans=0;
	(x<=m)&&(ans+=find(x,y,l(now),l,m));(y>m)&&(ans+=find(x,y,r(now),m+1,r));return ans;
}
I void swap(int &x,int &y){x^=y^=x^=y;}
struct linkcuttree{
	int fa[N*3],l[N*3],r[N*3],flag[N*3],st[N*3],sh,f[N*3],sum[N*3];
	I void up(int x){sum[x]=min(min(sum[l[x]],sum[r[x]]),f[x]);}
	I void push(int x){x&&(swap(l[x],r[x]),flag[x]^=1);}
	I void pushdown(int x){flag[x]&&(push(l[x]),push(r[x]),flag[x]=0);}
	I int child(int x){return l[fa[x]]==x||r[fa[x]]==x;}
	I int wrt(int x){return l[fa[x]]==x;}
	I void rotate(int x){
		int y=fa[x],z=fa[y],b=(l[y]==x?r[x]:l[x]);child(y)&&((y==l[z]?l[z]:r[z])=x);
		(x==l[y])?(r[x]=y,l[y]=b):(l[x]=y,r[y]=b);fa[x]=z;fa[y]=x;b&&(fa[b]=y);up(y);up(x);
	}
	I void splay(int x){
		int y=x;st[sh=1]=x;while(child(y)) st[++sh]=y=fa[y];while(sh) pushdown(st[sh--]);
		while(child(x)) child(fa[x])&&(rotate(wrt(x)^wrt(fa[x])?x:fa[x]),0),rotate(x);
	}
	I void access(int x){for(int y=0;x;x=fa[y=x])splay(x),r[x]=y,up(x);}
	I void makeroot(int x){access(x);splay(x);push(x);}
	I void split(int x,int y){makeroot(x);access(y);splay(y);}
	I void link(int x,int y){makeroot(x);fa[x]=y;}
	I void cut(int x,int y){split(x,y);r[y]=fa[x]=0;up(y);}
	I int findroot(int x){access(x);splay(x);while(l[x]) pushdown(x),x=l[x];return splay(x),x;}
}s;
I void link(int x,int y,int id){s.link(x,id+n);s.link(y,id+n);}
I void cut(int x,int y,int id){s.cut(x,id+n);s.cut(id+n,y);}
int main(){
	freopen("1.in","r",stdin);
	freopen("2.out","w",stdout);
	register int i;
	scanf("%d%d%d%d",&n,&m,&k,&op);s.f[0]=s.sum[0]=1e9;
	for(i=1;i<=n;i++) s.f[i]=1e9;
	for(i=1;i<=m;i++) scanf("%d%d",&x[i],&y[i]),s.f[i+n]=i;
	for(i=1;i<=m;i++){
		a=x[i];b=y[i];if(a==b){d[i]=m+1;continue;}if(s.findroot(a)^s.findroot(b)){link(a,b,i);continue;}
		s.split(a,b);now=s.sum[b];d[i]=now+1;cut(x[now],y[now],now);link(a,b,i);
	}
	for(i=1;i<=m;i++)root[i]=root[i-1],get(d[i],root[i]);
	while(k--)scanf("%d%d",&a,&b),op&&(a=(a+lastans)%m+1,b=(b+lastans)%m+1),(a>b)&&(swap(a,b),0),printf("%d\n",lastans=(n-(find(0,a,root[b])-find(0,a,root[a-1]))));
}
posted @ 2021-03-13 21:01  275307894a  阅读(53)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end