P5385 [Cnoi2019]须臾幻境
作者:互联网
题意
首先联通块个数等于总点数-生成森林的边数,于是我们考虑维护原图的一棵生成树。
将边依次加入,用lct维护时间的最大生成树,并记录每条边在哪条边加入时删去,没被删则为\(0\),设为\(f_i\)。
考虑一次询问,我们查询下\([l,r]\)内\(f_i\leqslant r\)的数的个数,这样我们就能知道这个区间被删了多少条边。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxn=4e5+10;
const int inf=1e9;
int n,m,Q,type,lastans;
struct Edge{int u,v;}E[maxn];
inline int read()
{
char c=getchar();int res=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
return res*f;
}
int fa[maxn],val[maxn],minn[maxn],f[maxn];
int ch[maxn][2];
bool rev[maxn];
inline bool checkroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
inline int get(int x){return ch[fa[x]][1]==x;}
inline void up(int x){minn[x]=min(val[x],min(minn[ch[x][0]],minn[ch[x][1]]));}
inline void rotate(int x)
{
int y=fa[x],z=fa[y],k=get(x),w=ch[x][k^1];
if(!checkroot(y))ch[z][get(y)]=x;ch[x][k^1]=y,ch[y][k]=w;
if(w)fa[w]=y;fa[y]=x;fa[x]=z;
up(y),up(x);
}
inline void reverse(int x){swap(ch[x][0],ch[x][1]);rev[x]^=1;}
inline void down(int x)
{
if(!rev[x])return;
if(ch[x][0])reverse(ch[x][0]);
if(ch[x][1])reverse(ch[x][1]);
rev[x]=0;
}
inline void splay(int x)
{
int now=x;
stack<int>sta;
sta.push(now);
while(!checkroot(now))sta.push(fa[now]),now=fa[now];
while(!sta.empty())down(sta.top()),sta.pop();
while(!checkroot(x))
{
int y=fa[x];
if(!checkroot(y))rotate(get(x)==get(y)?y:x);
rotate(x);
}
}
inline void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),ch[x][1]=y,up(x);}
inline void makeroot(int x){access(x);splay(x);reverse(x);}
inline int findroot(int x)
{
access(x);splay(x);
while(ch[x][0])down(x),x=ch[x][0];
splay(x);
return x;
}
inline void split(int x,int y){makeroot(x);access(y);splay(y);}
inline void link(int x,int y){makeroot(x);fa[x]=y;}
inline void cut(int x,int y){split(x,y);ch[y][0]=fa[x]=0;up(y);}
inline int query(int x,int y){split(x,y);return minn[y];}
int tot;
int root[maxn];
struct Segment_tree
{
#define lc(p) (seg[p].lc)
#define rc(p) (seg[p].rc)
#define sum(p) (seg[p].sum)
int lc,rc,sum;
}seg[maxn<<5];
void insert(int pre,int &p,int l,int r,int pos)
{
seg[p=++tot]=seg[pre];sum(p)++;
if(l==r)return;
int mid=(l+r)>>1;
if(pos<=mid)insert(lc(pre),lc(p),l,mid,pos);
else insert(rc(pre),rc(p),mid+1,r,pos);
}
int query(int p,int l,int r,int ql,int qr)
{
if(l>=ql&&r<=qr)return sum(p);
int mid=(l+r)>>1,res=0;
if(ql<=mid)res+=query(lc(p),l,mid,ql,qr);
if(qr>mid)res+=query(rc(p),mid+1,r,ql,qr);
return res;
}
int main()
{
n=read(),m=read(),Q=read(),type=read();
for(int i=0;i<=n;i++)val[i]=minn[i]=inf;
for(int i=1;i<=m;i++)val[i+n]=minn[i+n]=i;
for(int i=1;i<=m;i++)
{
E[i].u=read(),E[i].v=read();
if(E[i].u==E[i].v){f[i]=i;continue;}
if(findroot(E[i].u)==findroot(E[i].v))
{
int pos=query(E[i].u,E[i].v);
f[pos]=i;
cut(E[pos].u,pos+n),cut(E[pos].v,pos+n);
}
link(E[i].u,i+n),link(E[i].v,i+n);
}
for(int i=1;i<=m;i++)
{
root[i]=root[i-1];
if(f[i])insert(root[i-1],root[i],0,m,f[i]);
}
while(Q--)
{
int l=read(),r=read();
if(type)l=(l+lastans)%m+1,r=(r+lastans)%m+1;
if(l>r)swap(l,r);
int tmp=query(root[r],0,m,0,r)-query(root[l-1],0,m,0,r);
printf("%d\n",lastans=n-(r-l+1-tmp));
}
return 0;
}
标签:int,void,Cnoi2019,幻境,fa,while,P5385,read,inline 来源: https://www.cnblogs.com/nofind/p/13041469.html