CF1392I

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);
	}
}
原文地址:https://www.cnblogs.com/chasedeath/p/14748863.html