2200+专项:F. Nauuo and Portals(构造 并查集)

原题: http://codeforces.com/contest/1173/problem/F

题意:

n n n*n 网格 ( 1 , 1 ) ( n , n ) (1,1)-(n,n) ,n个人从左往右 ( i , 0 ) (i,0) ,n个人从上往下 ( 0 , i ) (0,i) ,你可以放多对传送门,来改变这些人的运动轨迹。

要满足左边第 i i 个人走到 ( a i , n + 1 ) (a_i,n+1) ,右边第 i i 个人走到 ( n + 1 , b i ) (n+1,b_i) ,其中 a i a_i 不会重复, b i b_i 也是。

解析:

5
3 1 5 4 2
4 2 1 3 5

一个一个来,以上面的案例为例。左边第二个人要走到第一行,就放一个 ( 2 , 1 ) (2,1) ,上面第三个人走到第一列,放 ( 1 , 3 ) (1,3)
在这里插入图片描述
接下来是左边5走到2,上面2走到2。

为了满足上面的两个,我们在第一行和第一列不会放了。所以从第二行和第二列开始。
在这里插入图片描述
此时发现,你需要维护一个并查集,表示由之前的传送门的影响,还没有满足的点的动向。
在这里插入图片描述
代码:

#include<bits/stdc++.h>
using namespace std;
#define pill pair<int,int>
const int maxn=1009;
int a[maxn],b[maxn];
int pos[2][maxn];

vector<pill>V;
int fin(int id,int a){
    return pos[id][a]==a?a:pos[id][pos[id][a]]=fin(id,pos[id][a]);
}
int main(){
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++)pos[0][i]=pos[1][i]=i;
    for(int i=1,j;i<=n;i++)scanf("%d",&j),a[j]=i;
    for(int i=1,j;i<=n;i++)scanf("%d",&j),b[j]=i;
    for(int i=1;i<=n;i++){
        int h=fin(0,a[i]),c=fin(1,b[i]);
        if(h==i&&c==i){
            continue;
        }
        V.push_back({h,i}),V.push_back({i,c});
        pos[0][i]=h;
        pos[1][i]=c;
    }
    printf("%d\n",(int)V.size()/2);
    for(int i=0;i<V.size();i+=2){
        printf("%d %d %d %d\n",V[i].first,V[i].second,V[i+1].first,V[i+1].second);
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/91403448