[loj3525]喷泉公园

先将整张图$x$和$y$​都缩小一半,即"道路"长度变为1,"长椅"变为放在格子中心

如果在没有长椅的限制下也无解(直接dfs即可判定),显然原问题也无解

否则,将所有格子(注意不是点)黑白染色,并强制横向道路(即从$(x,y)$到$(x+1,y)$的道路,纵向同理)对应的长椅在黑色格子的中心、纵向道路对应的长椅在白色格子的中心

在这个限制(构造)下,长椅的限制即变为黑(白)色格子的上下(左右)两边不同时为横(纵)向道路

从上到下、从左到右依次贪心选边(能选即选),简单画图不难发现合法

为了方便,可以使用map维护,复杂度为$o(n\log n)$

 1 #include<bits/stdc++.h>
 2 #include"parks.h"
 3 using namespace std;
 4 #define N 200005
 5 #define vi vector<int>
 6 #define pii pair<int,int>
 7 #define mp make_pair
 8 #define fi first
 9 #define se second
10 int n,id[N],f[N];
11 pii a[N];
12 vi ansu,ansv,ansa,ansb;
13 map<int,int>mat[N],vis[N];
14 bool cmp(int x,int y){
15     return a[x]<a[y];
16 }
17 int find(int k){
18     if (k==f[k])return k;
19     return f[k]=find(f[k]);
20 }
21 void add(int x,int y,pii z){
22     vis[z.fi][z.se]=1;
23     f[find(x)]=find(y);
24     ansu.push_back(x-1);
25     ansv.push_back(y-1);
26     ansa.push_back(z.fi*2+1);
27     ansb.push_back(z.se*2+1);
28 }
29 int construct_roads(vi x,vi y){
30     n=x.size();
31     for(int i=1;i<=n;i++){
32         a[i]=mp(x[i-1]/2,y[i-1]/2);
33         id[i]=f[i]=mat[a[i].fi][a[i].se]=i;
34     }
35     sort(id+1,id+n+1,cmp);
36     for(int j=1;j<=n;j++){
37         int i=id[j],k=mat[a[i].fi+1][a[i].se];
38         if ((k)&&(find(i)!=find(k))){
39             if ((a[i].fi+a[i].se)&1)add(i,k,a[i]);
40             else{
41                 if (!vis[a[i].fi][a[i].se-1])add(i,k,mp(a[i].fi,a[i].se-1));
42             }
43         }
44         k=mat[a[i].fi][a[i].se+1];
45         if ((k)&&(find(i)!=find(k))){
46             if ((a[i].fi+a[i].se)%2==0)add(i,k,a[i]);
47             else{
48                 if (!vis[a[i].fi-1][a[i].se])add(i,k,mp(a[i].fi-1,a[i].se));
49             }
50         }
51     }
52     for(int i=1;i<=n;i++)
53         if (find(i)!=find(1))return 0;
54     build(ansu,ansv,ansa,ansb);
55     return 1;
56 } 
View Code

 

posted @ 2021-07-26 21:51  PYWBKTDA  阅读(58)  评论(0编辑  收藏  举报