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

    3514: Codechef MARCH14 GERALD07加强版

    Time Limit: 60 Sec  Memory Limit: 256 MB
    Submit: 2162  Solved: 828
    [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

    By zhonghaoxi

    分析:挺好的一道题.

       知道了如何利用点的信息来求连通块的个数这道题就好做了. 那么需要维护哪些信息? 怎么求呢?

       按照编号一条一条边地加,如果当前加的这条边i的两个端点已经连通了,则找到这两个点的路径上编号最小的边j. 用i替代它,并令id[i] = j.  要求[L,R]的连通块的数量,就是n - [L,R]中有多少条边的id<L.

       至于为什么,这个要脑补一下. 一开始是有n个点组成了n个连通块,如果一条边的id ≥ L,那么就会形成一个环,连通块的数量不变,如果id < L,那么就会将连通块连起来,合并成一个连通块,连通块的数量减少1.非常神奇.

       至于怎么求id,这就是LCT的经典应用了,类似于bzoj2594,但是要注意:bzoj2594每次是求最大的边,这道题中是求最小的边,符号要变过来,一开始val要初始化为inf.

       知道了id后,问题就变成了每次统计区间[L,R]中有多少个id[ai] < L. 统计有多少个,满足区间可减性. 统计的数与权值id有关,能想到什么?主席树!

       求连通块数量的这么一种方法要记住了.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 400010;
    int n,m,Q,type,lastans,f[maxn],id[maxn],val[maxn],cnt,root[maxn];
    int fa[maxn],son[maxn][2],rev[maxn],sta[maxn],maxx[maxn],tot;
    
    struct node
    {
        int x,y;
    }e[maxn];
    
    struct node2
    {
        int num,lson,rson;
    }tr[maxn * 20];
    
    int find(int x)
    {
        if (x == f[x])
            return x;
        return f[x] = find(f[x]);
    }
    
    bool is_root(int x)
    {
        return son[fa[x]][0] != x && son[fa[x]][1] != x;
    }
    
    bool get(int x)
    {
        return son[fa[x]][1] == x;
    }
    
    void pushdown(int x)
    {
        if (rev[x])
        {
            rev[son[x][0]] ^= 1;
            rev[son[x][1]] ^= 1;
            rev[x] = 0;
            swap(son[x][0],son[x][1]);
        }
    }
    
    void pushup(int x)
    {
        maxx[x] = x;
        if (son[x][0])
            if (val[maxx[son[x][0]]] < val[maxx[x]])
                maxx[x] = maxx[son[x][0]];
        if (son[x][1])
            if (val[maxx[son[x][1]]] < val[maxx[x]])
                maxx[x] = maxx[son[x][1]];
    }
    
    void turn(int x)
    {
        int y = fa[x];
        int z = fa[y];
        int temp = get(x);
        if (!is_root(y))
            son[z][son[z][1] == y] = x;
        fa[x] = z;
        son[y][temp] = son[x][temp ^ 1];
        fa[son[y][temp]] = y;
        son[x][temp ^ 1] = y;
        fa[y] = x;
        pushup(y);
        pushup(x);
    }
    
    void splay(int x)
    {
        int top = 0;
        sta[++top] = x;
        for (int y = x; !is_root(y); y = fa[y])
            sta[++top] = fa[y];
        for (int i = top; i >= 1; i--)
            pushdown(sta[i]);
        for (int temp; !is_root(x); turn(x))
        {
            if (!is_root(temp = fa[x]))
            {
                if (get(temp) == get(x))
                    turn(temp);
                else
                    turn(x);
            }
        }
    }
    
    void Access(int x)
    {
        int t = 0;
        for (; x; t = x,x = fa[x])
        {
            splay(x);
            son[x][1] = t;
            pushup(x);
        }
    }
    
    void Reverse(int x)
    {
        Access(x);
        splay(x);
        rev[x] ^= 1;
    }
    
    void Cut(int x,int y)
    {
        Reverse(x);
        Access(y);
        splay(y);
        fa[x] = son[y][0] = 0;
    }
    
    void Link(int x,int y)
    {
        Reverse(x);
        fa[x] = y;
        splay(x);
    }
    
    int query(int x,int y)
    {
        Reverse(x);
        Access(y);
        splay(y);
        return maxx[y];
    }
    
    void insert(int l,int r,int x,int &y,int v)
    {
        tr[y = ++tot] = tr[x];
        tr[y].num++;
        if (l == r)
            return;
        int mid = (l + r) >> 1;
        if (v <= mid)
            insert(l,mid,tr[x].lson,tr[y].lson,v);
        else
            insert(mid + 1,r,tr[x].rson,tr[y].rson,v);
    }
    
    int Query(int l,int r,int x,int y,int v)
    {
        if (r == v)
            return tr[y].num - tr[x].num;
        int mid = (l + r) >> 1;
        if (v <= mid)
            return Query(l,mid,tr[x].lson,tr[y].lson,v);
        else
            return tr[tr[y].lson].num - tr[tr[x].lson].num + Query(mid + 1,r,tr[x].rson,tr[y].rson,v);
    }
    
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&Q,&type);
        for (int i = 1; i <= n; i++)
            f[i] = i;
        memset(val,127/3,sizeof(val));
        for (int i = 1 + n; i <= m + n; i++)
            val[i] = i - n;
        for (int i = 1; i <= m; i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            e[i].x = x;
            e[i].y = y;
            if (x == y)
            {
                id[i] = i;
                continue;
            }
            int fx = find(x),fy = find(y);
            if (fx != fy)
            {
                Link(x,i + n);
                Link(i + n,y);
                f[fx] = fy;
                id[i] = 0;
            }
            else
            {
                int temp = query(x,y);
                int temp2 = val[temp];
                Cut(e[temp2].x,temp);
                Cut(temp,e[temp2].y);
                Link(x,i + n);
                Link(i + n,y);
                id[i] = temp2;
            }
        }
        for (int i = 1; i <= m; i++)
            insert(0,m,root[i - 1],root[i],id[i]);
        for (int i = 1; i <= Q; i++)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            if (type == 1)
            {
                l ^= lastans;
                r ^= lastans;
            }
            printf("%d
    ",lastans = (n - Query(0,m,root[l - 1],root[r],l - 1)));
        }
    
        return 0;
    }
  • 相关阅读:
    react-native Image resizeMode
    常见的前端设计模式
    Execution failed for task ':app:transformClassesAndResourcesWithProguardForRelease'.
    Error: [mobx] Since strict-mode is enabled, changing observed observable values outside actions is not allowed. Please wrap the code in an `action` if this change is intended.
    react-native 扫一扫功能(二维码扫描)功能开发
    字符串截取 及 substr 和 substring 的区别
    POST请求的forHTTPHeaderField
    使用MDScratchImageView实现刮奖效果
    计算Pan手势到指定点的角度
    CAShapeLayer的使用[2]
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8536895.html
Copyright © 2011-2022 走看看