bzoj3514 GERALD07

求出每个边加入后构成环弹出最早进来的那个边是什么,问题转化为求l-r中那个值小于l的个数num,答案为n-num

LCT+主席树可以做。。。

/**************************************************************
    Problem: 3514
    User: Clare
    Language: C++
    Result: Accepted
    Time:33684 ms
    Memory:62604 kb
****************************************************************/
 
#include <cstdio> 
#include <iostream> 
#include <algorithm> 
#include <cstring> 
#include <cmath> 
#include <queue> 
#include <vector> 
#include <stack> 
using namespace std; 
   
#define N 400010 
#define INF 0x7fffffff
   
int n,m,K,tot,type,Ans; 
int fa[N],c[N][2],Min[N],v[N],smg[N],A[N][2]; 
struct Node{ 
    int L,R; 
    int sum; 
}t[N*10]; 
int root[N]; 
bool Rev[N]; 
stack<int> st; 
   
inline int read() 
{ 
    int x=0,f=1;char ch=getchar(); 
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 
    while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();} 
    return x*f;  
} 
   
void Updata(int &i,int l,int r,int val) 
{ 
    t[++tot]=t[i];i=tot; 
    t[i].sum++; 
    if(l==r) 
        return; 
    int mid=(l+r)/2; 
    if(val<=mid) 
        Updata(t[i].L,l,mid,val); 
    else Updata(t[i].R,mid+1,r,val); 
} 
   
int Query(int i,int j,int l,int r,int val) 
{ 
    if(l==r) 
    { 
        return t[i].sum-t[j].sum; 
    } 
    int mid=(l+r)/2; 
    if(val<=mid) 
        return Query(t[i].L,t[j].L,l,mid,val); 
    else return t[t[i].L].sum-t[t[j].L].sum+Query(t[i].R,t[j].R,mid+1,r,val); 
} 
   
bool Pd_root(int k) 
{ 
    return !(c[fa[k]][0]==k)&&!(c[fa[k]][1]==k); 
} 
   
void Pushup(int k) 
{ 
    int l=c[k][0],r=c[k][1]; 
    Min[k]=k; 
    if(v[Min[k]]>v[Min[l]])Min[k]=Min[l]; 
    if(v[Min[k]]>v[Min[r]])Min[k]=Min[r]; 
} 
   
void Pushdown(int k) 
{ 
    int l=c[k][0],r=c[k][1]; 
    if(Rev[k]) 
    { 
        Rev[k]^=1;Rev[l]^=1;Rev[r]^=1; 
        swap(c[k][0],c[k][1]); 
    } 
} 
   
void Rotate(int x) 
{ 
    int y=fa[x],z=fa[y],l,r; 
    if(c[y][0]==x)l=0;else l=1; 
    r=l^1; 
    if(Pd_root(y)); 
    else if(c[z][0]==y)c[z][0]=x; 
    else c[z][1]=x; 
    fa[x]=z;fa[y]=x;fa[c[x][r]]=y; 
    c[y][l]=c[x][r];c[x][r]=y; 
    Pushup(y);Pushup(x); 
} 
 
void Splay(int x)
{
    int i;
    for(i=x;!Pd_root(i);i=fa[i])
        st.push(i);
    st.push(i);
    while(!st.empty())
    {
        int now=st.top();st.pop();
        Pushdown(now);
    }
    while(!Pd_root(x))
    {
        int y=fa[x],z=fa[y];
        if(!Pd_root(y))
        {
            if(c[z][0]==y^c[y][0]==x)
                Rotate(x);
            else Rotate(y);
        }
        Rotate(x);
    }
}
 
void Access(int x)
{
    for(int t=0;x;t=x,x=fa[x])
        Splay(x),c[x][1]=t,Pushup(x);
}
 
void Move_to_root(int x)
{
    Access(x);Splay(x);Rev[x]^=1;
}
 
void Join(int x,int y)
{
    Move_to_root(x);fa[x]=y;Pushup(x);
}
 
void Cut(int x,int y)
{
    Move_to_root(x);Access(y);Splay(y);
    if(c[y][0]==x)
        c[y][0]=fa[x]=0;
    else c[y][1]=fa[x]=0;
    Pushup(y);Pushup(x);
}
 
int Find_root(int x)
{
    Access(x);Splay(x);
    while(c[x][0])
        x=c[x][0];
    return x;
}
 
void Split(int x,int y)
{
    Move_to_root(x);Access(y);Splay(y);
}
 
int main() 
{ 
    n=read();m=read();K=read();type=read();
    Min[0]=0;v[0]=INF;
    for(int i=1;i<=n;i++)
        Min[i]=i,v[i]=INF;
    for(int i=1;i<=m;i++)
    {
        A[i][0]=read();A[i][1]=read();
        if(A[i][0]==A[i][1])
        {
            smg[i]=i;continue;
        }
        v[i+n]=i;Min[i+n]=i+n;
        if(Find_root(A[i][0])==Find_root(A[i][1]))
        {
            Split(A[i][0],A[i][1]);
            int t=Min[A[i][1]];smg[i]=v[t];
            Cut(t,A[t-n][0]);Cut(t,A[t-n][1]);
            Join(i+n,A[i][0]);Join(i+n,A[i][1]);
        }
        else
        {
            smg[i]=0;
            Join(i+n,A[i][0]);Join(i+n,A[i][1]);
        }
    }
    for(int i=1;i<=m;i++)
    {
        root[i]=root[i-1];
        Updata(root[i],1,200000,smg[i]+1);
    }
    for(int i=1;i<=K;i++)
    {
        int l=read(),r=read();
        if(type)
        {
            l=l^Ans;r=r^Ans;
        }
        if(l>r)
            Ans=0;
        else
            Ans=n-Query(root[r],root[l-1],1,200000,l);
        printf("%d\n",Ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值