CF1392I - Kevin and Grid

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)

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);
	}
}
posted @ 2021-05-09 21:03  chasedeath  阅读(88)  评论(0编辑  收藏  举报