• luoguP5385 [Cnoi2019]须臾幻境


    题意

    首先联通块个数等于总点数-生成森林的边数,于是我们考虑维护原图的一棵生成树。

    将边依次加入,用lct维护时间的最大生成树,并记录每条边在哪条边加入时删去,没被删则为(0),设为(f_i)

    考虑一次询问,我们查询下([l,r])(f_ileqslant 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
    ",lastans=n-(r-l+1-tmp));
    	}
    	return 0;
    }
    
  • 相关阅读:
    POJ 2386 Lake Counting
    POJ 1852 Ants
    HDU 4570 Multi-bit Trie
    HDU 4611 Balls Rearrangement
    ZOJ 3551 Bloodsucker
    HEU 百题解1001 谁是中间的那个
    BNU 1001 北师大ACM新手指导/ICPC introduction(1)
    BOJ 1580 Shoot
    BOJ 1578 Maximum
    BOJ 1577 Easy Game
  • 原文地址:https://www.cnblogs.com/nofind/p/13041469.html
Copyright © 2020-2023  润新知