一道神奇的并查集

Posted JayWang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一道神奇的并查集相关的知识,希望对你有一定的参考价值。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
template<class T> inline void read(T &_a){
    bool f=0;int _ch=getchar();_a=0;
    while(_ch<0 || _ch>9){if(_ch==-)f=1;_ch=getchar();}
    while(_ch>=0 && _ch<=9){_a=(_a<<1)+(_a<<3)+_ch-0;_ch=getchar();}
    if(f)_a=-_a;
}

struct fff{int x,y;}node[100001];
int n,m,q,e,mp[4][2010][2010],res;
bool del[2010][2010];

inline void erase(int x,int y)
{
    if(del[x][y]) return ;
    del[x][y]=true;
    ++res;
    --mp[0][x][y];
    ++mp[1][x][y];
    --mp[2][x][y];
    ++mp[3][x][y];
}

inline int findx(int o,int x,int y)
{
    return mp[o][x][y]==x?x:mp[o][x][y]=findx(o,mp[o][x][y],y);
}

inline int findy(int o,int x,int y)
{
    return mp[o][x][y]==y?y:mp[o][x][y]=findy(o,x,mp[o][x][y]);
}

inline void up(int k)
{
    for (register int i=1;i<=e;++i)
    {
        int x=min(node[i].x,n),y=node[i].y;
        node[i].x-=k;
        if(y<1||y>m) continue;
        if(x<1) continue;
        while(x>0&&x>=node[i].x)
        {
            x=findx(0,x,y);
            if(x>0&&x>=node[i].x) erase(x,y);
        }
    }
}

inline void down(int k)
{
    for (register int i=1;i<=e;++i)
    {
        int x=max(node[i].x,1),y=node[i].y;
        node[i].x+=k;
        if(y<1||y>m) continue;
        if(x>n) continue;
        while(x>0&&x<=node[i].x&&x<=n)
        {
            x=findx(1,x,y);
            if(x>0&&x<=node[i].x&&x<=n) erase(x,y);
        }
    }
}

inline void left(int k)
{
    for (register int i=1;i<=e;++i)
    {
        int y=min(node[i].y,m),x=node[i].x;
        node[i].y-=k;
        if(x<1||x>n) continue;
        if(y<1) continue;
        while(y>0&&y>=node[i].y)
        {
            y=findy(2,x,y);
            if((y>0&&y>=node[i].y)) erase(x,y);
        }
    }
}

inline void right(int k)
{
    for (register int i=1;i<=e;++i)
    {
        int y=max(node[i].y,1),x=node[i].x;
        node[i].y+=k;
        if(x<1||x>n) continue;
        if(y>m) continue;
        while(y>0&&y<=node[i].y&&y<=m)
        {
            y=findy(3,x,y);
            if(y>0&&y<=node[i].y&&y<=m) erase(x,y);
        }
    }
}

int main()
{
    read(n); read(m); read(e); read(q);
    for (register int i=1;i<=n;++i)
        for (register int v=1;v<=m;++v)
            mp[0][i][v]=mp[1][i][v]=i,mp[2][i][v]=mp[3][i][v]=v;
    for (register int i=1;i<=e;++i) read(node[i].x),read(node[i].y);
    for (register int i=1;i<=e;++i) erase(node[i].x,node[i].y);
    for (register int i=1;i<=n;++i) node[++e].x=i,node[e].y=0,node[++e].x=i,node[e].y=m+1;
    for (register int i=1;i<=m;++i) node[++e].x=0,node[e].y=i,node[++e].x=n+1,node[e].y=i;
    while(q--)
    {
        register char op=getchar();
        while(op!=R&&op!=L&&op!=D&&op!=U) op=getchar();
        register int k; read(k);
        res=0;
        if(op==R) left(k);
        else if (op==L) right(k);
        else if (op==D) up(k);
        else down(k);
        printf("%d\n",res);
    }
    return 0;
}

 

以上是关于一道神奇的并查集的主要内容,如果未能解决你的问题,请参考以下文章

几道莫名AC的并查集题

带逆向思维的并查集

BZOJ 3319 黑白树

计蒜客 奶酪 (并查集)

并查集(入门)

阿里一次面试:周芷若和韩小昭的并查集