BZOJ3514: Codechef MARCH14 GERALD07加强版

题解:  很久以前写的一道题 刚开始找不到切入点 我们这样考虑吧 对于每个查询 我们查询当前加入[l,r]边的联通快的个数 那么我们从联通块的本身出发 当前的联通块的个数应该等于n-关键路径的条数 关键路径等于总路径-无用路径的条数 那么我们怎么去判断一条路径是无用的呢 当且仅当 你加入这条边形成环的最小标号是无用路径 然后主席数维护区间无用路径的条数即可

/**************************************************************
    Problem: 3514
    User: c20161007
    Language: C++
    Result: Accepted
    Time:37272 ms
    Memory:134500 kb
****************************************************************/
 
#include <bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
const int MAXN=4e5+10;
const int inf=1e9+10;
using namespace std;
ll readll(){
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int readint(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
int minn[MAXN],ch[MAXN][2],key[MAXN],pre[MAXN],res[MAXN],fa[MAXN],n,m,q,type,cnt;
int root[MAXN];
bool rt[MAXN];
void Treavel(int x)
{
    if(x)
    {
    //  cout<<x<<endl;
        Treavel(ch[x][0]);
        printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d 最小值 %2d,key=%2d\n",x,ch[x][0],ch[x][1],pre[x],minn[x],key[x]);
        Treavel(ch[x][1]);
    }
}
void debug(int rp)
{
    printf("root:%d\n",rp);
    Treavel(rp);
}
void reverse(int r){
    if(!r) return ;
    swap(ch[r][0],ch[r][1]);
    res[r]^=1;
}
void push(int r){
    if(res[r]){
        reverse(ch[r][0]);
        reverse(ch[r][1]);
        res[r]^=1;
    }
}
void up(int r){
    if(!r) return ;
    minn[r]=r;
    if(key[minn[ch[r][0]]]<key[minn[r]]) minn[r]=minn[ch[r][0]];
    if(key[minn[ch[r][1]]]<key[minn[r]]) minn[r]=minn[ch[r][1]];
}
void P(int r){
    if(!rt[r]) P(pre[r]);
    push(r);
}
void rotate(int x,int kind){
    int y=pre[x];
    pre[ch[x][kind]]=y;ch[y][!kind]=ch[x][kind];
    if(rt[y]) rt[y]=0,rt[x]=1;
    else ch[pre[y]][ch[pre[y]][1]==y]=x;
    pre[x]=pre[y];ch[x][kind]=y;pre[y]=x;
    up(y);
}
void splay(int x){
    P(x);
    while(!rt[x]){
        if(rt[pre[x]]) rotate(x,ch[pre[x]][0]==x);
        else{
            int y=pre[x];int kind=ch[pre[y]][0]==y;
            if(ch[y][kind]==x) rotate(x,!kind),rotate(x,kind);
            else rotate(y,kind),rotate(x,kind);
        }
    }
    up(x);
}
void access(int x){
    int y=0;
    while(x){
        splay(x);
        if(ch[x][1]) rt[ch[x][1]]=1,pre[ch[x][1]]=x;
        ch[x][1]=y;
        up(x);
        if(y) rt[y]=0;
        y=x;x=pre[x];
    }
}
void mroot(int u){
    access(u);splay(u);
    reverse(u);
}
bool pd(int u,int v){
    while(pre[u]) u=pre[u];
    while(pre[v]) v=pre[v];
    return u==v;
}
void Link(int u,int v){
    mroot(u);pre[u]=v;
}
void destory(int u,int v){
    mroot(u);access(v);splay(v);
    rt[u]=rt[v]=1;pre[u]=pre[v]=0;ch[v][0]=0;
    up(v);up(u);
}
int querty(int u,int v){
    mroot(u);access(v);splay(v);
//  debug(v);
    //cout<<u<<" "<<v<<" "<<minn[v]<<endl;
    return minn[v];
}
void newnode(int t){
    rt[t]=1;res[t]=pre[t]=ch[t][0]=ch[t][1]=0;minn[t]=t;key[t]=inf;
}
pii w[MAXN];
typedef struct node{
    int l,r,sum;
}node;
node d[25*MAXN];
void update(int &x,int y,int l,int r,int t){
    cnt++;x=cnt;d[x]=d[y];d[x].sum--;
    //cout<<l<<" "<<r<<" "<<t<<" "<<d[x].sum<<endl;
    if(l==r) return ;
    int mid=(l+r)>>1;
    if(t<=mid) update(d[x].l,d[y].l,l,mid,t);
    else update(d[x].r,d[y].r,mid+1,r,t);
}
int ans;
void querty1(int x,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){
        //cout<<l<<" "<<r<<" "<<d[x].sum<<endl;
        ans+=d[x].sum;
        return ;
    }
    int mid=(l+r)>>1;
    if(ql<=mid) querty1(d[x].l,l,mid,ql,qr);
    if(qr>mid) querty1(d[x].r,mid+1,r,ql,qr);
}
int main(){
    ios::sync_with_stdio(false);
    n=readint();m=readint();q=readint();type=readint();
    key[0]=inf;cnt=0;
    for(int i=1;i<=n+m;i++) newnode(i);
    int u,v;
    for(int i=1;i<=m;i++){
        u=readint();v=readint();w[i].first=u;w[i].second=v;
        if(u==v){
            fa[i]=i;continue;
        }
        //cout<<pd(u,v)<<endl;
        if(!pd(u,v)){
            fa[i]=0;key[i+n]=i;Link(u,i+n);Link(v,i+n);
            //cout<<i<<" "<<key[i+n]<<endl;
        }
        else{
            int t=querty(u,v);int tt=key[t];
            //cout<<t<<" "<<tt<<endl;
            fa[i]=tt;
            destory(t,w[tt].first);destory(t,w[tt].second);
            key[i+n]=i;
            Link(i+n,u);Link(i+n,v);
        }
    }
    //cout<<"sb"<<endl;
//  for(int i=1;i<=m;i++) cout<<fa[i]<<" ";
//  cout<<endl;
    for(int i=1;i<=m;i++){
        if(!fa[i]){
            root[i]=root[i-1];continue;
        }
        //cout<<"sb"<<endl;
        update(root[i],root[i-1],1,m,fa[i]);
        //cout<<"sb"<<endl;
    }
    int Lans=0;int l,r;
    for(int i=1;i<=q;i++){
        l=readint();r=readint();
        if(type==1) l^=Lans,r^=Lans;
        if(l>r) swap(l,r);
        ans=0;querty1(root[r],1,m,l,r);
        //cout<<ans<<endl;
        Lans=n-((r-l+1)+ans);
        printf("%d\n",Lans);
    }
    return 0;
}

 

3514: Codechef MARCH14 GERALD07加强版

Time Limit: 60 Sec  Memory Limit: 256 MB
Submit: 2363  Solved: 907
[Submit][Status][Discuss]

Description

N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。

Input

第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。
接下来M行,代表图中的每条边。
接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。

Output

 K行每行一个整数代表该组询问的联通块个数。

Sample Input

3 5 4 0
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2

Sample Output

2
1
3
1

HINT

对于100%的数据,1≤N、M、K≤200,000。


2016.2.26提高时限至60s

Source

posted @ 2018-08-18 21:07  wang9897  阅读(134)  评论(0编辑  收藏  举报