题目
Time Limits: 1000 ms Memory Limits: 262144 KB
Description
Input
Output
Sample Input
5 3 0
1 4 5
1 2 4
3 1 2
Sample Output
3
Data Constraint
题解
鸟(雀)题一道。。。
做法:函数式线段树+lct
在每一次加入一条边i的时候,我们记录一个last[i]
如果在当前情况下加入了这一条边之后构成了一个环,last[i]就表示这个环里面最小的边的编号(也就是最早加进来的边),然后我们把这条边删除并且把这条边加进来
如果没有构成环我们就直接把这一条边加进来并且last[i]=0
然后对于询问(l,r),答案就是n减去x∈[l,r] last[x]∈[0,l)的数量
原因就是:
如果last[x]∈[l,x),就表示如果我们依次加入l–r的边,那么在加到边x的时候边x对应的两个点已经属于一个联通块了,连上这一条边并不会减少一个联通块,反之则会减少一个联通块
对于删边,我们发现只会删去最后一条边,所以我们可以用一个函数式线段树来实现这样的删除
对于重边我们需要进行特殊的处理,这个也比较简单
一开始我判断两个点是否在同一个联通块的判断函数打错了,我天真的以为和cut是一样的
后来仔细想了想cut是因为两个点之间有边,换根之后两个点的深度肯定一个是1一个是2所以这样打才是对的,但是判断函数不是
于是就想到了把x,y都换根一次,看看y换完之后x还是不是根,这样就可以判断了
贴代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fo1(i,b,a) for(i=b;i>=a;i--)
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
const int maxn=2e6+5;
int tree[maxn*2][4],fa[maxn],son[maxn][3],mi[maxn];
int la[maxn],a[maxn][3],root[maxn],d[maxn];
bool bz[maxn];
int i,j,k,m,n,x,y,q,ty,ans,p,now,z,u,v,o,zsc,l,r;
char ch;
int read(){
int x=0;
ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9'){
x=x*10+ch-48;
ch=getchar();
}
return x;
}
bool isroot(int x){
if (son[fa[x]][1]!=x && son[fa[x]][2]!=x) return true; else return false;
}
void remark(int x){
if (bz[x]){
bz[x]=false;
bz[son[x][1]]^=1;
bz[son[x][2]]^=1;
int t=son[x][1];
son[x][1]=son[x][2]; son[x][2]=t;
}
}
void update(int x){
mi[x]=mi[son[x][1]];
if (mi[son[x][2]] &&(mi[x]==0 || mi[x]>mi[son[x][2]])) mi[x]=mi[son[x][2]];
if (x>n && (mi[x]==0 || mi[x]>x-n)) mi[x]=x-n;
}
void rotate(int x,int w){
int y=fa[x];
son[y][3-w]=son[x][w];
if (son[x][w]) fa[son[x][w]]=y;
if (!isroot(y)){
if (son[fa[y]][1]==y) son[fa[y]][1]=x; else son[fa[y]][2]=x;
}
fa[x]=fa[y];
fa[y]=x;
son[x][w]=y;
update(y); update(x);
}
void splay(int x){
int i,y;
d[0]=0;
while (!isroot(x)){
d[++d[0]]=x;
x=fa[x];
}
d[++d[0]]=x;
fo1(i,d[0],1) remark(d[i]);
x=d[1];
while (!isroot(x)){
y=fa[x];
if (isroot(y)){
if (x==son[y][1]) rotate(x,2); else rotate(x,1);
} else{
if (y==son[fa[y]][1]){
if (x==son[y][1]){
rotate(y,2); rotate(x,2);
} else{
rotate(x,1); rotate(x,2);
}
} else{
if (x==son[y][2]){
rotate(y,1); rotate(x,1);
} else{
rotate(x,2); rotate(x,1);
}
}
}
}
}
void access(int x){
for(int t=0;x;x=fa[x]) splay(x),son[x][2]=t,update(x),t=x;
}
void makeroot(int x){
access(x); splay(x); bz[x]^=1;
}
void link(int x,int y){
makeroot(x); fa[x]=y;
}
void cut(int x,int y){
makeroot(x); access(y); splay(y); son[y][1]=0; fa[x]=0; update(y);
}
int find(int x,int y){
makeroot(x); access(y); splay(y); return mi[y];
}
bool tong(int x,int y){
makeroot(x); makeroot(y);
if (isroot(x)) return false; else return true;
}
void maketree(int v,int l,int r,int x){
tree[++p][1]=tree[v][1]; tree[p][2]=tree[v][2]; tree[p][3]=tree[v][3]+1;
if (l==r) return;
int mid=(l+r)/2;
if (x<=mid){
tree[p][1]=p+1;
maketree(tree[v][1],l,mid,x);
} else{
tree[p][2]=p+1;
maketree(tree[v][2],mid+1,r,x);
}
}
void find(int zo,int yo,int l,int r,int x,int y){
if (l==x && r==y){
z=z+tree[yo][3]-tree[zo][3];
} else{
int mid=(l+r)/2;
if (y<=mid) find(tree[zo][1],tree[yo][1],l,mid,x,y); else
if (x>mid) find(tree[zo][2],tree[yo][2],mid+1,r,x,y); else{
find(tree[zo][1],tree[yo][1],l,mid,x,mid);
find(tree[zo][2],tree[yo][2],mid+1,r,mid+1,y);
}
}
}
int main(){
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
n=read(); q=read(); ty=read();
fo(zsc,1,q){
z=read();
if (z==1){
u=read(); v=read(); if (ty){
u=1+(u xor ans)%n; v=1+(v xor ans)%n;
}
++now;
a[now][1]=u; a[now][2]=v;
if (u==v){
root[now]=root[now-1];
continue;
}
if (! tong(u,v)){
mi[now+n]=now;
link(u,now+n); link(v,now+n);
} else{
o=find(u,v);
la[now]=o;
cut(o+n,a[o][1]);
cut(o+n,a[o][2]);
mi[now+n]=now;
link(u,now+n);
link(v,now+n);
}
root[now]=p+1;
maketree(root[now-1],0,q,la[now]);
a[now][1]=u; a[now][2]=v;
} else if (z==2){
if (a[now][1]==a[now][2]){
now--;
continue;
}
cut(n+now,a[now][1]);
cut(n+now,a[now][2]);
if (la[now]){
mi[la[now]+n]=la[now];
link(a[la[now]][1],la[now]+n);
link(a[la[now]][2],la[now]+n);
}
la[now]=0;
now--;
} else{
x=read(); y=read();
if (ty){
u=1+(x xor ans)%now; v=1+(y xor ans)%now;
x=min(u,v);
y=max(u,v);
}
z=0;
find(root[x-1],root[y],0,q,0,x-1);
ans=n-z;
printf("%d\n",ans);
}
}
return 0;
}