CF1392I - Kevin and Grid
题目大意
给定一张网格图,每个点上((i,j))写着(a_i+b_j)
对于一个给定阈值(x),将图分为(a_i+b_j<x)和(a_i+b_jge 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_jleq x)的个数,还多组查询,你猜猜要干嘛....
比较不用过脑子的,做7次FFT乘法即可,也可以共用一些FFT结果
$downarrow downarrow downarrow $我没有脑子!!! (/ha/ha/ha/ha/ha)
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
",ans);
}
}