UVALive 4730 Kingdom(并查集加 线段树或树状数组)

题意:有T组测试数据,每组数据的N表示有N个城市,接下来的N行里每行给出每个城市的坐标(0<=x,y<=1000000),然后有M(1<M<200000)个操作,操作有两类,(1)"road A B",表示将城市A和城市B通过一条道路连接,如果A和B原来属于不同的城市群,经过这个操作,A和B就在一个城市群里了,保证每条道路不会和其他道路相交(除了端点A和B)。(2)"line C",表示查询当穿过y=C的直线,有多少个城市群、这几个城市群一共有多少个城市。

        用并查集维护每个城市群的的最大的y值和最小的y值,以及这个城市群内有多少个点。
        每次更新的时候,先把原先城市群里的东西从线段树里去掉,更新好这个城市群之后,再放下去。
        不过,用线段树要离散化,麻烦了点,写了两树状数组。分别维护有多少个state和city.

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=2000005;
int y[N];
int fa[N],irank[N],iy1[N],iy2[N];
int find_fa(int x)
{
    if(fa[x]==x) return x;
    else return fa[x]=find_fa(fa[x]);
}
void unin(int a,int b)
{
    int x=find_fa(a),y=find_fa(b);
    if(x==y) return;
    else
    {
        fa[x]=y;
        irank[y]+=irank[x];
    }
}
struct BIT
{
    int data[N],limit;
    void init(int a)
    {
        limit=a;
        memset(data,0,sizeof(int)*(limit+5));
    }
    void updata(int x,int y,int valu)
    {
        while(x>=1)
        {
            data[x]-=valu;
            x-=(x&(-x));
        }
        while(y>=1)
        {
            data[y]+=valu;
            y-=(y&(-y));
        }
    }
    int query(int x)
    {
        int sum=0;
        while(x<=limit)
        {
            sum+=data[x];
            x+=(x&(-x));
        }
        return sum;
    }
}state,city;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m,imax=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            b*=2;
            y[i]=b;
            fa[i]=i; irank[i]=1; iy1[i]=b; iy2[i]=b;
            imax=max(imax,b);
        }
        state.init(imax);   city.init(imax);

        scanf("%d",&m);
        for(int i=0;i<m;i++)
        {
            char str[30];
            scanf("%s",str);
            if(strcmp(str,"road")==0)
            {
                int a,b,x,y;
                scanf("%d%d",&a,&b);
                x=find_fa(a),y=find_fa(b);
                if(x==y) continue;
                if(irank[x]==1&&irank[y]==1)
                {
                    unin(a,b);
                    int fa=find_fa(a);
                    iy1[fa]=min(iy1[a],iy1[b]);    iy2[fa]=max(iy2[a],iy2[b]);

                    state.updata(iy1[fa]-1,iy2[fa],1);
                    city.updata(iy1[fa]-1,iy2[fa],irank[fa]);
                }
                else if(irank[x]==1||irank[y]==1)
                {
                    if(irank[x]==1) swap(x,y);
                    state.updata(iy1[x]-1,iy2[x],-1);
                    city.updata(iy1[x]-1,iy2[x],-irank[x]);
                    unin(a,b);
                    int fa=find_fa(a);
                    iy1[fa]=min(iy1[fa],min(iy1[x],iy1[y]));
                    iy2[fa]=max(iy2[fa],max(iy2[x],iy2[y]));
                    state.updata(iy1[fa]-1,iy2[fa],1);
                    city.updata(iy1[fa]-1,iy2[fa],irank[fa]);
                }
                else
                {
                    state.updata(iy1[x]-1,iy2[x],-1);
                    state.updata(iy1[y]-1,iy2[y],-1);

                    city.updata(iy1[x]-1,iy2[x],-irank[x]);
                    city.updata(iy1[y]-1,iy2[y],-irank[y]);

                    unin(a,b);
                    int fa=find_fa(a);
                    iy1[fa]=min(iy1[fa],min(iy1[x],iy1[y]));
                    iy2[fa]=max(iy2[fa],max(iy2[x],iy2[y]));

                    state.updata(iy1[fa]-1,iy2[fa],1);
                    city.updata(iy1[fa]-1,iy2[fa],irank[fa]);
                }
            }
            else
            {
                int a,b;
                scanf("%d.%d",&a,&b);
                printf("%d %d\n",state.query(a*2+1),city.query(a*2+1));
            }
        }
    }
    return 0;
}


你可能感兴趣的:(UVALive 4730 Kingdom(并查集加 线段树或树状数组))