题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3514

题意:给出一个图m条边。每次询问只加入编号在区间[L,R]之内的边有多少连通块。在线。

思路:求出[1,i]边加入时的最大生成树,即加入在[1,i]中不在生成树上的边时连通块不变。假如是离线,那么我们按照询问右端点排序,每次维护区间[L,R]中在生成树上的边即可。

现在是在线,我们用可持久化线段树维护。直观想,每次加入一条边时连通块数减少1。但是加入边R时存在环的时候这个就不满足了。设这个环上编号最小的边的编号为x,那么x一旦加入,即L<=x<R时,那么加入R时连通块数就不会再减少。因此我们在函数式线段树中的[L,R]查找区间[0,L-1]的和即可。

struct node
{
    int Min,val,isReversed;
    node *c[2],*f;

    inline void reverse()
    {
        isReversed^=1;
        swap(c[0],c[1]);
    }
};

node a[N<<1],*nullNode;

inline void pushUp(node *p)
{
    if(p==nullNode) return;
    p->Min=p->val;
    if(p->c[0]!=nullNode) p->Min=min(p->Min,p->c[0]->Min);
    if(p->c[1]!=nullNode) p->Min=min(p->Min,p->c[1]->Min);
}

inline void pushDown(node *p)
{
    if(p->isReversed)
    {
        if(p->c[0]!=nullNode) p->c[0]->reverse();
        if(p->c[1]!=nullNode) p->c[1]->reverse();
        p->isReversed=0;
    }
}

inline void rotate(node *p,int k)
{
    node *q=p->f;
    q->c[k]=p->c[!k];
    if(p->c[!k]!=nullNode) p->c[!k]->f=q;
    p->c[!k]=q;
    p->f=q->f;
    if(q->f!=nullNode)
    {
        if(p->f->c[0]==q) p->f->c[0]=p;
        if(p->f->c[1]==q) p->f->c[1]=p;
    }
    q->f=p;
    pushUp(q);
}

inline int isRoot(node *p)
{
    return p->f==nullNode||p->f->c[0]!=p&&p->f->c[1]!=p;
}

void splay(node *p)
 {
     pushDown(p);
     while (!isRoot(p))
     {
         if(isRoot(p->f))
         {
             pushDown(p->f);
             pushDown(p);
             if(p==p->f->c[0]) rotate(p,0);
             else rotate(p,1);
         }
         else
         {
             pushDown(p->f->f);
             pushDown(p->f);
             pushDown(p);
             if(p->f->f->c[0]==p->f)
             {
                 if(p->f->c[0]==p) rotate(p->f,0);
                 else rotate(p,1);
                 rotate(p,0);
             }
             else
             {
                 if(p->f->c[1]==p) rotate(p->f,1);
                 else rotate(p,0);
                 rotate(p,1);
             }
         }
     }
     pushUp(p);
}

node* access(node *p)
{
    node *q=nullNode;
    while(p!=nullNode)
    {
        splay(p);
        p->c[1]=q;
        pushUp(p);
        q=p;
        p=p->f;
    }
    return q;
}

int connected(int x,int y)
{
    access(a+y);
    node *p=a+x;
    while(p!=nullNode)
    {
        splay(p);
        if(p->f==nullNode) break;
        p=p->f;
    }
    while(p->c[1]!=nullNode) p=p->c[1];
    return p==a+y;
}

void join(int x,int y)
{
    access(a+x);
    splay(a+x);
    a[x].reverse();
    a[x].f=a+y;
}

void cut(int x,int y)
{
    access(a+x);splay(a+y);
    if(a[y].f==a+x) a[y].f=nullNode;
    else
    {
        access(a+y);
        splay(a+x);
        a[x].f=nullNode;
    }
}

int query(int x,int y)
{
    access(a+x);
    node *p=a+y;
    node *q=nullNode;
    for(;p!=nullNode;p=p->f)
    {
        splay(p);
        if(p->f==nullNode)
        {
            int ans=p->val;
            if(q!=nullNode) ans=min(ans,q->Min);
            if(p->c[1]!=nullNode) ans=min(ans,p->c[1]->Min);
            return ans;
        }
        p->c[1]=q;
        q=p;
        pushUp(q);
    }
}

int n,m,Q;

struct segNode
{
    int L,R,sum;
};

segNode A[N*20];
int e;

int root[N<<1];

int add(int t,int L,int R,int p)
{
    int x=++e;
    if(L==R)
    {
        A[x].sum=A[t].sum+1;
        return x;
    }
    A[x].L=A[t].L;
    A[x].R=A[t].R;
    int M=(L+R)>>1;
    if(p<=M) A[x].L=add(A[t].L,L,M,p);
    else A[x].R=add(A[t].R,M+1,R,p);
    A[x].sum=A[A[x].L].sum+A[A[x].R].sum;
    return x;
}

int type;

int edge[N][2];

void init()
{
    nullNode=new node();
    nullNode->isReversed=0;
    nullNode->Min=INF;
    nullNode->val=INF;
    nullNode->c[0]=nullNode->c[1]=nullNode->f=nullNode;

    n=getInt();
    m=getInt();
    Q=getInt();
    type=getInt();
    int i;
    for(i=1;i<=n+m;i++)
    {
        if(i<=n) a[i].val=a[i].Min=INF;
        else a[i].val=a[i].Min=i-n;
        a[i].c[0]=a[i].c[1]=a[i].f=nullNode;
    }
    for(i=1;i<=m;i++) scanf("%d%d",&edge[i][0],&edge[i][1]);
    for(i=1;i<=m;i++)
    {
        int u=edge[i][0];
        int v=edge[i][1];
        if(u==v)
        {
            root[i]=root[i-1];
            continue;
        }
        if(connected(u,v))
        {
            int t=query(u,v);
            cut(n+t,edge[t][0]);
            cut(n+t,edge[t][1]);
            root[i]=add(root[i-1],0,m,t);
            join(i+n,u);
            join(i+n,v);
        }
        else
        {
            root[i]=add(root[i-1],0,m,0);
            join(i+n,u);
            join(i+n,v);
        }
    }
}

int query(int x,int y,int L,int R,int ll,int rr)
{
    if(L==ll&&R==rr) return A[x].sum-A[y].sum;
    int M=(L+R)>>1;
    if(rr<=M) return query(A[x].L,A[y].L,L,M,ll,rr);
    if(ll>M) return query(A[x].R,A[y].R,M+1,R,ll,rr);

    int ans=query(A[x].L,A[y].L,L,M,ll,M);
    ans+=query(A[x].R,A[y].R,M+1,R,M+1,rr);
    return ans;
}

int main()
{

    init();
    int ans=0;
    while(Q--)
    {
        int L=getInt();
        int R=getInt();
        if(type) L^=ans,R^=ans;
        ans=n-query(root[R],root[L-1],0,m,0,L-1);
        printf("%d\n",ans);
    }
}

BZOJ 3514 Codechef MARCH14 GERALD07加强版的更多相关文章

  1. BZOJ 3514: Codechef MARCH14 GERALD07加强版( LCT + 主席树 )

    从左到右加边, 假如+的边e形成环, 那么记下这个环上最早加入的边_e, 当且仅当询问区间的左端点> _e加入的时间, e对答案有贡献(脑补一下). 然后一开始是N个连通块, 假如有x条边有贡献 ...

  2. BZOJ 3514: Codechef MARCH14 GERALD07加强版 [LCT 主席树 kruskal]

    3514: Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 1312  Solved: 501 ...

  3. [BZOJ 3514]Codechef MARCH14 GERALD07加强版 (CHEF AND GRAPH QUERIES)

    [BZOJ3514] Codechef MARCH14 GERALD07加强版 (CHEF AND GRAPH QUERIES) 题意 \(N\) 个点 \(M\) 条边的无向图,\(K\) 次询问保 ...

  4. BZOJ 3514: Codechef MARCH14 GERALD07加强版(LCT + 主席树)

    题意 \(N\) 个点 \(M\) 条边的无向图,询问保留图中编号在 \([l,r]\) 的边的时候图中的联通块个数. \(K\) 次询问强制在线. \(1\le N,M,K \le 200,000\ ...

  5. 【刷题】BZOJ 3514 Codechef MARCH14 GERALD07加强版

    Description N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. Input 第一行四个整数N.M.K.type,代表点数.边数.询问数以及询问是否加密. 接下来 ...

  6. BZOJ 3514 Codechef MARCH14 GERALD07加强版 Link-Cut-Tree+划分树

    题目大意: 给定n个点m条边的无向图.求问当图中仅仅有[编号在[l,r]区间内]的边存在时图中的联通块个数 强制在线 注意联通块是指联通了就是同一块,不是Tarjan求的那种块 看到这题的那一刻我就想 ...

  7. BZOJ 3514: Codechef MARCH14 GERALD07加强版 (LCT维护最大生成树+主席树)

    题意 给出nnn个点,mmm条边.多次询问,求编号在[l,r][l,r][l,r]内的边形成的联通块的数量,强制在线. 分析 LCTLCTLCT维护动态最大生成树,先将每条边依次加进去,若形成环就断掉 ...

  8. 【BZOJ-3514】Codechef MARCH14 GERALD07加强版 LinkCutTree + 主席树

    3514: Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 1288  Solved: 490 ...

  9. 【LCT+主席树】BZOJ3514 Codechef MARCH14 GERALD07加强版

    3514: Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 2023  Solved: 778 ...

随机推荐

  1. AMBA interconnector PL301(一)

    HPM(High-Performance Matrix)是一个自生成的AMBA3 bus subsystem. 由一个AXI bus matrix,Frequency Conversion Compo ...

  2. 《zw版Halcon与delphi系列原创教程》发布说明

    <zw版Halcon与delphi系列原创教程>发布说明 zw转载的<台湾nvp系列halcon-delphi教程>,虽然很多,不过基本上都是从cnc.数控角度的demo..  ...

  3. 【fedora】强制解除yum锁定

    运行yum makecache时出现yum update时候出现Another app is currently holding the yum lock解决方法yum被锁定了. 可以通过执行 rm ...

  4. WCF技术的不同应用场景及其实现分析

    这一篇文章,是总结一下WCF技术,以及基于这个技术发展出来的几个典型应用场景,并且我将尝试对这些不同的WCF实现的原理进行一些比较分析. 关于WCF这个技术的基本概念,如果你不是很清楚,可以参考一下有 ...

  5. 作为一个web开发人员,哪些技术细节是在发布站点前你需要考虑到的

    前日在cnblogs上看到一遍文章<每个程序员都必读的12篇文章>,其中大多数是E文的. 先译其中一篇web相关的”每个程序员必知之WEB开发”. 原文: http://programme ...

  6. UITableView(转)

    一.UITableView概述 UITableView继承自UIScrollView,可以表现为Plain和Grouped两种风格,分别如下图所示:          其中左边的是Plain风格的,右 ...

  7. CSS中的各个选择节点,都有样式最后一个无样式的快捷解决方法

    2.1.3 多标签 多标签选择器一般和html上下文有关,它有以下集中分类 选择一个祖先的所有子孙节点,例如 div p{…} 选择一个父元素的所有直属节点,例如 div > p{…} 选择某一 ...

  8. mysql的sql文件的备份与还原

    1.备份 $mysqldump –u root –p*** dbname > filename.sql 2.还原 前提是数据库必须存在 $mysql  –u root –p*** dbname ...

  9. linux源码Makefile详解(完整)【转】

    转自:http://www.cnblogs.com/Daniel-G/p/3286614.html 随着 Linux 操作系统的广泛应用,特别是 Linux 在嵌入式领域的发展,越来越多的人开始投身到 ...

  10. Linux 进程状态【转】

    转自:http://www.cnblogs.com/itech/p/3208261.html 来自: http://blog.csdn.net/tianlesoftware/article/detai ...