CF1392I - Kevin and Grid

题目大意

给定一张网格图,每个点上$(i,j)$写着$a_i+b_j$

对于一个给定阈值$x$,将图分为$a_i+b_j<x$和$a_i+b_j\ge x$两组连通块

定义一个能够连通到网格图边界的连通块的价值为1,否则为2

有$q$次查询,每次给定$x$,求两种连通块价值之差


分析

是网格图上的连通块计数,并且看起来无法真的搜索连通块,于是想到平面图的欧拉定理

欧拉定理连通块计数式子$C=|V|-|E|+|F|-1$

考虑和题目给定的奇妙的价值有什么关系

显然价值是连通块个数加上被包含的连通块个数

答案应该是$S_1-S_2=|V_1|-|V_2|-|E_1|+|E_2|+|F_1|-|F_2|+1类被包含个数-2类被包含个数$

容易观察发现,当一个1类连通块被包含时,$F_2$就增加1

也就是说$1类被包含个数-|F_2|$最终只剩下 :外层无限区域 以及 四相邻连通块

设四个相邻连通块的个数为$D_1,D_2$

那么$S_1-S_2=|V_1|-|V_2|-|E_1|+|E_2|+D_1-D_2$

关于如何统计$a_i+b_j\leq x$的个数,还多组查询,你猜猜要干嘛….

比较不用过脑子的,做7次FFT乘法即可,也可以共用一些FFT结果

$\downarrow \downarrow \downarrow $我没有脑子!!! (/ha/ha/ha/ha/ha)

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
const int N=1<<18;
const db PI=acos(-1);

struct Cp{
db a,b;
Cp(){ }
Cp(db a,db b):a(a),b(b){ }
Cp operator + (const Cp _) const{ return Cp(a+_.a,b+_.b); }
Cp operator - (const Cp _) const{ return Cp(a-_.a,b-_.b); }
Cp operator * (const Cp _) const{ return Cp(a*_.a-b*_.b,a*_.b+b*_.a); }
} R[N];
int rev[N];
void FFT(Cp *a,int f){
rep(i,0,N-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
static Cp e[N>>1];
e[0]=Cp(1,0);
for(int i=1;i<N;i<<=1) {
Cp t(cos(PI/i),f*sin(PI/i));
for(int j=i-2;j>=0;j-=2) e[j+1]=(e[j]=e[j>>1])*t;
for(int l=0;l<N;l+=i*2){
for(int j=l;j<l+i;++j) {
Cp t=a[j+i]*e[j-l];
a[j+i]=a[j]-t;
a[j]=a[j]+t;
}
}
}
if(f==-1) rep(i,0,N-1) a[i].a/=N;
}

// 这个变量名求轻喷
int n,m,q;
int a[N],b[N];
ll A[N],B[N],C[N],D1[N],D2[N];
// A为<x块个数
// B为<x边数
// C为>=x边数
// D1,D2同上述

Cp D[N],E[N],F[N],G[N],H[N],I[N];

void Add(ll *a,Cp *b,Cp *c) {
rep(i,0,N-1) R[i]=b[i]*c[i];
FFT(R,-1);
rep(i,0,N-1) a[i]+=round(R[i].a);
}

int main(){
rep(i,0,N-1) rev[i]=(rev[i>>1]>>1)|((i&1)*(N/2));
n=rd(),m=rd(),q=rd();
rep(i,1,n) {
D[a[i]=rd()].a++;
if(i>1) F[max(a[i-1],a[i])].a++, G[min(a[i-1],a[i])].a++;
}
rep(i,1,m) {
E[b[i]=rd()].a++;
if(i>1) H[max(b[i-1],b[i])].a++, I[min(b[i-1],b[i])].a++;
}
FFT(D,1),FFT(E,1); FFT(F,1),FFT(G,1); FFT(H,1),FFT(I,1);
Add(A,D,E);
Add(B,D,H),Add(B,F,E);
Add(C,D,I),Add(C,G,E);
Add(D1,F,H),Add(D2,G,I);
rep(i,1,N-1) A[i]+=A[i-1],B[i]+=B[i-1],D1[i]+=D1[i-1];
drep(i,N-2,0) C[i]+=C[i+1],D2[i]+=D2[i+1];
while(q--) {
int x=rd();
ll ans=1ll*n*m-2*A[x-1]-C[x]+B[x-1]+D2[x]-D1[x-1];
printf("%lld\n",ans);
}
}