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

    Description

    给定 (n) 个点 (m) 条边的无向图,每次询问保留图中编号在 ([l,r]) 的边的时候图中联通块个数。强制在线。

    (n,mleq 2cdot 10^5)

    Solution

    先考虑一下假如可以离线的话怎么做。

    把询问按照右端点排序,维护边权 最大生成树,这里的"边权"指的是边的标号。

    每次尝试加边,如果这条边连接的两条边不连通就直接加,否则从环上找一条边权最小的边替换,然后用线段树维护当前用了哪条边,如果要加入就对应位置 (+1),要删除就对应位置 (-1) 。维护生成树的过程用 (LCT) 实现。这样对于询问 ([l,r]) 就查一下在线段树上 ([l,r]) 的权值和 (sum) 表示当前在图上用到了 (sum) 条边,(n-sum) 即为答案。

    然后考虑在线做法。

    把线段树换成主席树就好了。

    大概扫了一下网上的题解好像做法都是搞出来一个 (ntr[i]) 表示加入第 (i) 条边的时候替换掉了哪条边,如果没有替换掉边则值为 (0)。然后每次询问的时候找主席树 ([0,l-1])(sum) 就好了。。。然而我并不能想明白为什么是这样,只能用我那种有加有减的做法了...

    Code

    #include<bits/stdc++.h>
    using std::min;
    using std::max;
    using std::swap;
    using std::vector;
    typedef double db;
    typedef long long ll;
    #define pb(A) push_back(A)
    #define pii std::pair<int,int>
    #define all(A) A.begin(),A.end()
    #define mp(A,B) std::make_pair(A,B)
    const int N=4e5+5;
    #define ls ch[x][0]
    #define rs ch[x][1]
    
    int ch[N][2],fa[N],mn[N],stk[N],father[N];
    int n,m,k,type,val[N],idx[N],rev[N],top,rt[N];
    
    struct Edge{
        int x,y;
    }edge[N];
    
    void pushup(int x){
        mn[x]=min(mn[ls],min(mn[rs],val[x]));
    }
    
    void pushr(int x){
        swap(ls,rs);rev[x]^=1;
    }
    
    void pushdown(int x){
        if(rev[x]) pushr(ls),pushr(rs),rev[x]=0;
    }
    
    bool nroot(int x){
        return ch[fa[x]][0]==x or ch[fa[x]][1]==x;
    }
    
    int find(int x){
        return father[x]==x?x:father[x]=find(father[x]);
    }
    
    void rotate(int x){
        int y=fa[x],z=fa[y],d=ch[y][1]==x,dd=ch[z][1]==y;
        ch[y][d]=ch[x][d^1];if(ch[x][d^1]) fa[ch[x][d^1]]=y;
        fa[x]=z;if(nroot(y)) ch[z][dd]=x;
        ch[x][d^1]=y;fa[y]=x;pushup(y);
    }
    
    void splay(int x){
        int now=x;stk[++top]=now;
        while(nroot(now)) now=fa[now],stk[++top]=now;
        while(top) pushdown(stk[top--]);
        while(nroot(x)){
            int y=fa[x],z=fa[y];
            if(nroot(y)) rotate((ch[y][1]==x)^(ch[z][1]==y)?x:y);
            rotate(x);
        } pushup(x);
    }
    
    void access(int x){
        for(int y=0;x;y=x,x=fa[x])
            splay(x),rs=y;pushup(x);
    }
    
    void makeroot(int x){
        access(x),splay(x),pushr(x);
    }
    
    void link(int x,int y){
        makeroot(x);fa[x]=y;
    }
    
    void cut(int x,int y){
        makeroot(x),access(y),splay(y);
        fa[x]=ch[y][0]=0;pushup(y);
    }
    
    void split(int x,int y){
        makeroot(x),access(y),splay(y);
    }
    
    int getint(){
        int X=0,w=0;char ch=getchar();
        while(!isdigit(ch))w|=ch=='-',ch=getchar();
        while( isdigit(ch))X=X*10+ch-48,ch=getchar();
        if(w) return -X;return X;
    }
    
    namespace hjt{
        int tot,ch[N*40][2],sum[N*40];
    
        void update(int &x,int las,int l,int r,int ql,int qr,int c){
            x=++tot;
            sum[x]=sum[las]+c;ls=ch[las][0];rs=ch[las][1];
            if(l==r) return;
            int mid=l+r>>1;
            ql<=mid?update(ls,ch[las][0],l,mid,ql,qr,c):update(rs,ch[las][1],mid+1,r,ql,qr,c);
        }
    
        int query(int las,int x,int l,int r,int ql,int qr){
            if(ql<=l and r<=qr) return sum[x]-sum[las];
            int mid=l+r>>1,ans=0;
            if(ql<=mid) ans+=query(ch[las][0],ls,l,mid,ql,qr);
            if(mid<qr) ans+=query(ch[las][1],rs,mid+1,r,ql,qr);
            return ans;
        }
    
    };
    
    signed main(){
        mn[0]=1e9;
        n=getint(),m=getint(),k=getint(),type=getint();
        for(int i=1;i<=m;i++){
            int x=getint(),y=getint();
            edge[i]=(Edge){x,y};val[i+n]=i;
        }
        for(int i=0;i<=n;i++) father[i]=i,val[i]=1e9;
        for(int i=1;i<=m;i++){
            rt[i]=rt[i-1];
            int r1=find(edge[i].x),r2=find(edge[i].y);
            if(r1!=r2){
                hjt::update(rt[i],rt[i],0,m,i,i,1); 
                father[r1]=r2;
            } else{
                if(edge[i].x==edge[i].y) continue;
                split(edge[i].x,edge[i].y);
                int xx=mn[edge[i].y];
                hjt::update(rt[i],rt[i],0,m,xx,xx,-1);
                hjt::update(rt[i],rt[i],0,m,i,i,1);
                cut(edge[xx].x,xx+n),cut(edge[xx].y,xx+n);
            }
            link(edge[i].x,i+n),link(edge[i].y,i+n);
        } int lasans=0;
        while(k--){
            int l=getint(),r=getint();
            if(type) l^=lasans,r^=lasans;
            int p=hjt::query(rt[l-1],rt[r],0,m,l,r);
            printf("%d
    ",lasans=n-p);
        } return 0;
    }
    
    
  • 相关阅读:
    配置DHCP Snooping防止DHCP Server仿冒者攻击示例
    初识kbmmw 的多语言支持
    kbmmw 5.16.0 发布
    sql去除注释
    markdown写ppt
    Kafka流处理内幕详解
    【转载】matplotlib.pyplot的使用总结大全(入门加进阶)
    魔方第三层旋转公式
    自动化机器学习方面的开源框架和商业服务列表
    进阶版OFA算法:CompOFA: Compound Once-for-all Networks
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/10143656.html
Copyright © 2011-2022 走看看