zoukankan      html  css  js  c++  java
  • Codechef MARCH14 GERALD07加强版

    强制在线不代表不能预处理!

    考虑暴力怎么干?

    开始n个联通块。now=n

    不断加入边,如果连接两个联通块,--now

    否则不动。

    后者的前提是和[l,id-1]的边构成环

    所以,我们考虑每个[l,r]中出现的边能否第一次连接两个联通块

    预处理:

    编号从小到大加入每条边,LCT维护树上“边”编号最小值和最小值位置

    如果加入边e没有环,那么说明无论什么时候[l,r]询问包含e的时候,e总能是第一个连接两个联通块的边,设ti[e]=0,表示不能替换边

    如果会成环,那么把编号最小的边删掉,ti[i]=被删边的编号。意义是,只有[l,r]不包含这条被删除的边的时候,e才会贡献。

        如果包含,那么这个环一定会连出来;如果不包含,e和这个环上其他的边不会构成环,加入e的时候有贡献。(如果会构成环,那么环上边和被删边之前也能构成环,矛盾)

    所以,ti[i]在不在[l,r]之中,唯一对应了i能否真正连接两个联通块!

    所以对于询问,主席树维护即可。[l,r]中,ti[i]<l的数的个数sum,n-sum就是ans

    实现细节:
    LCT的编号别和原边的编号混了。。。。

    mi是最小边编号(最小值),id是最小值的lct点的编号!

    调半天~~~

    吸取重组病毒的教训,把主席树封装进namespace~~

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=200000+5;
    const int inf=0x3f3f3f3f;
    struct bian{
        int x,y;
    }e[N];
    int n,m,k,typ;
    int ti[N];
    namespace seg{
    #define mid ((l+r)>>1)
    struct node{
        int ls,rs;
        int val;
    }t[N*22];
    int cnt;
    int rt[N];
    void upda(int &x,int y,int l,int r,int to){
        x=++cnt;
        t[x].val=t[y].val+1;
        if(l==r) return;
        t[x].ls=t[y].ls,t[x].rs=t[y].rs;
        if(to<=mid) upda(t[x].ls,t[y].ls,l,mid,to);
        if(mid<to) upda(t[x].rs,t[y].rs,mid+1,r,to);
    }
    int query(int x,int y,int l,int r,int L,int R){
        //cout<<" l r "<<l<<" "<<r<<" : "<<t[x].val<<" "<<t[y].val<<" "<<L<<" "<<R<<endl;
        if(L<=l&&r<=R){
            //cout<<" l r "<<l<<" "<<r<<" : "<<t[x].val<<" "<<t[y].val<<" "<<L<<" "<<R<<endl;
            return t[x].val-t[y].val;
        }
        int ret=0;
        if(L<=mid) ret+=query(t[x].ls,t[y].ls,l,mid,L,R);
        if(mid<R) ret+=query(t[x].rs,t[y].rs,mid+1,r,L,R);
        return ret;
    }
    void add(int x,int to){
        upda(rt[x],rt[x-1],0,m,to);
    }
    }
    namespace lct{
    #define ls t[x].ch[0]
    #define rs t[x].ch[1]
    struct node{
        int ch[2];
        int fa,r;
        int id;
        int mi;
        int d;
    }t[2*N];
    int sta[N];
    int cnt;
    bool nrt(int x){
        return (t[t[x].fa].ch[0]==x||t[t[x].fa].ch[1]==x);
    }
    void pushup(int x){
        if(t[t[x].ch[0]].mi<=t[x].d&&t[t[x].ch[0]].mi<=t[t[x].ch[1]].mi){
            t[x].mi=t[t[x].ch[0]].mi;
            t[x].id=t[t[x].ch[0]].id;
        }
        else if(t[t[x].ch[1]].mi<=t[x].d&&t[t[x].ch[1]].mi<=t[t[x].ch[0]].mi){
            t[x].mi=t[t[x].ch[1]].mi;
            t[x].id=t[t[x].ch[1]].id;
        }
        else t[x].mi=t[x].d,t[x].id=x;
    }
    void rev(int x){
        swap(t[x].ch[0],t[x].ch[1]);
        t[x].r^=1;
    }
    void pushdown(int x){
        if(t[x].r){
            rev(t[x].ch[1]),rev(t[x].ch[0]);
            t[x].r=0;
        }
    }
    void rotate(int x){
        int y=t[x].fa,d=t[y].ch[1]==x;
        t[t[y].ch[d]=t[x].ch[!d]].fa=y;
        if(nrt(y)) t[t[x].fa=t[y].fa].ch[t[t[y].fa].ch[1]==y]=x;
        else t[x].fa=t[y].fa;
        t[t[x].ch[!d]=y].fa=x;
        pushup(y);
    }
    void splay(int x){
        int y=x,z=0;
        sta[++z]=y;
        while(nrt(y)) y=t[y].fa,sta[++z]=y;
        while(z) pushdown(sta[z--]);
        
        while(nrt(x)){
            y=t[x].fa,z=t[y].fa;
         //   cout<<"splaying "<<x<<" "<<y<<" "<<z<<endl; 
            if(nrt(y)){
                rotate(((t[z].ch[1]==y)==(t[y].ch[1]==x))?y:x);
            }
            rotate(x);
        }
        pushup(x);
    }
    void access(int x){
        for(reg y=0;x;y=x,x=t[x].fa){
            
            splay(x);t[x].ch[1]=y;pushup(x);
        //    cout<<" access xx "<<x<<" "<<t[x].fa<<endl;
        }
    }
    void makert(int x){
        access(x);splay(x);rev(x);
    }
    int findrt(int x){
        access(x);splay(x);
    //    cout<<" after splay "<<x<<endl;
        pushdown(x);
        while(t[x].ch[0]) {
            x=t[x].ch[0],pushdown(x);
    //        cout<<"findrt xx "<<x<<endl;
        }
        splay(x);
        return x;
    }
    int link(int x,int y,int d){
    //    cout<<" link "<<x<<" "<<y<<" : "<<d<<" cnt "<<cnt<<endl;
        makert(x);
    //    cout<<" makert "<<endl;
        ++cnt;
        t[cnt].d=d;
        t[cnt].id=cnt;
        t[cnt].mi=d;
        if(findrt(y)!=x){
        //    cout<<" new "<<endl;
            access(y);splay(y);
            t[x].fa=cnt;
            t[cnt].fa=y;
            return 0;
        }    
        pushup(x);
        splay(x);
        int kil=t[x].id;
        int lp=t[x].mi;
    //    cout<<" ---------------------kil "<<kil<<endl;
        splay(kil);
    //    cout<<" kilfa "<<t[kil].fa<<endl;
        t[t[kil].ch[0]].fa=0;
        t[t[kil].ch[1]].fa=0;
        makert(x);
        splay(x);splay(y);
        t[x].fa=cnt;
        t[cnt].fa=y;
        //cout<<" t[x].id "<<t[x].id<<" t[y].id "<<t[y].id<<endl;
        return lp;
    }
    }
    int main(){
        lct::t[0].id=-1;
        lct::t[0].d=inf;
        lct::t[0].mi=inf;
        rd(n);rd(m);rd(k);rd(typ);
        for(reg i=1;i<=n;++i) lct::t[i].d=inf,lct::t[i].id=-1,lct::t[i].mi=inf;
        lct::cnt=n;
        int x,y;
        for(reg i=1;i<=m;++i){
            rd(x);rd(y);
            if(x!=y) ti[i]=lct::link(x,y,i);
            else ti[i]=i;
            //cout<<" ii "<<i<<" "<<ti[i]<<endl;
        }
        for(reg i=1;i<=m;++i){
            seg::add(i,ti[i]);
        }
        int l,r;
        int las=0;
        while(k--){
            rd(l);rd(r);
            if(typ==1) l^=las,r^=las;
            int tmp=seg::query(seg::rt[r],seg::rt[l-1],0,m,0,l-1);
            printf("%d
    ",n-tmp);
            las=n-tmp;
        }
        return 0;
    }
    
    }
    signed main(){
    //freopen("data.in","r",stdin);
    //    freopen("my.out","w",stdout);
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2018/12/30 21:24:18
    */
    
    
        

     思路和区间数颜色挺像的!都是把贡献放在第一个能贡献的位置统计上!

    并且方法也是类似的:离线:排序扫描线+树状数组,在线:主席树

  • 相关阅读:
    asp.net 学习连接
    学习笔记一
    windows 2008 r2 AD密码策略
    Windows Server 2008 R2之活动目录回收站
    用java 调用 .net 自定义的 Soap WEB Service
    昆明赶街时间
    Windows Server 2008 R2 AD的备份和恢复
    AD 自定义属性
    AD、IIS、asp.net
    wsgen与wsimport命令说明
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10201419.html
Copyright © 2011-2022 走看看