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\n",lastans = (n - Query(0,m,root[l - 1],root[r],l - 1)));
    }

    return 0;
}

 

posted @ 2018-03-09 22:58  zbtrs  阅读(180)  评论(0编辑  收藏  举报