【CF1214G】Feeling Good 题解

题目大意

  有一个 n×mn\times m 的黑白棋盘,初始时候每个格子都是白色。
  接下来 qq 次操作,每次把第 aia_i 行的 [li,ri][l_i,r_i] 这个区间反色。
  每次操作结束就会问你,是否存在 x1,y1,x2,y2x_1,y_1,x_2,y_2,满足

  • 1x1<x2n1 \leq x_1 < x_2 \leq n
  • 1y1<y2m1 \leq y_1 < y_2 \leq m
  • (x1,y1)(x_1,y_1)(x2,y2)(x_2,y_2) 同色
  • (x1,y2)(x_1,y_2)(x2,y1)(x_2,y_1) 同色
  • (x1,y1)(x_1,y_1)(x2,y1)(x_2,y_1) 异色(即:对于矩形的四个角,对角同色,同侧异色)

  若存在,则输出其中一组解。

  n,m2000, q5×105n,m \leq 2000,~q \leq 5\times 10^5

题解

  为什么我想到每一列建一个 bitset 然后搞不出来,结果最后是每一行建一个 bitset 就特 tm 方便

  给每一行维护一个 bitset,表示这一行的染色情况。
  维护很好维护,每次就第 aia_i 行异或一段全 11 的东西就好了。

  然后看怎么找答案。如果某两行的 bitset 不是互相包含的关系(假设是第 x1x_1 行和第 x2x_2 行),那么存在 y1y_1,它在 x1x_1 那里为 11 而在 x2x_2 那里为 00,也存在 y2y_2,它在 x1x_1 那里为 00 而在 x2x_2 那里为 11。那这个 (x1,y1,x2,y2)(x_1,y_1,x_2,y_2) 就是答案。

  所以现在是要判断是否存在两行,它们不是互相包含的关系。然后题解给了一个很 nice 的方法,把所有的 bitset 按 size 排序,那么只需判断相邻的是否全都是包含关系即可。若相邻的全是包含关系,则任选两个都是包含关系(因为这形成了一条链),就会无解,否则把不是包含关系的那个相邻对拿出来算答案就行了。
  这个就用两个 set 维护一下,一个维护排序的 bitset,一个维护答案。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

const int maxn=2005;

struct BST{
int i,cnt;
};
bool operator < (const BST &a,const BST &b) {return a.cnt<b.cnt || a.cnt==b.cnt && a.i<b.i;}

int n,m,q;
bitset<maxn> B[maxn],flp[maxn];
set<BST> S;
set<pair<int,int>> Ans;

bitset<maxn> common;
bool cmp(int x,int y)
{
common=B[x]&B[y];
return (common!=B[x] && common!=B[y]);
}

void modify(int i,int cnt,int ty)
{
set<BST>::iterator it=S.find((BST){i,cnt}), mae, tsugi=it; // 最近好像学日语学疯了
tsugi++;
if (it!=S.begin())
{
mae=it; mae--;
int x=mae->i, y=it->i;
if (ty==-1) Ans.erase(make_pair(x,y));
else if (cmp(x,y)) Ans.insert(make_pair(x,y));
}
if (tsugi!=S.end())
{
int x=it->i, y=tsugi->i;
if (ty==-1) Ans.erase(make_pair(x,y));
else if (cmp(x,y)) Ans.insert(make_pair(x,y));
}
if (it!=S.begin() && tsugi!=S.end())
{
int x=mae->i, y=tsugi->i;
if (ty==1) Ans.erase(make_pair(x,y));
else if (cmp(x,y)) Ans.insert(make_pair(x,y));
}
}

bitset<maxn> b1,b2;
int main()
{
scanf("%d %d %d",&n,&m,&q);

fo(i,1,n) S.insert((BST){i,0});
fo(i,1,m) flp[i]=flp[i-1], flp[i][i]=1;

while (q--)
{
int a,l,r;
scanf("%d %d %d",&a,&l,&r);

int cnt=B[a].count();
modify(a,cnt,-1);
S.erase((BST){a,cnt});
B[a]^=((flp[r]>>l)<<l);
cnt=B[a].count();
S.insert((BST){a,cnt});
modify(a,cnt,1);

if (Ans.empty()) puts("-1"); else
{
set<pair<int,int>>::iterator it=Ans.begin();
int x1=it->first, x2=it->second;
common=B[x1]&B[x2];
b1=B[x1]^common, b2=B[x2]^common;
int y1=b1._Find_first(), y2=b2._Find_first();
if (x1>x2) swap(x1,x2);
if (y1>y2) swap(y1,y2);
printf("%d %d %d %d\n",x1,y1,x2,y2);
}
}
}