CF1392I

CF1392I

给定 \(n\times m\) 的矩形,给定长度为 \(n,m\) 的数列 \(\{a\},\{b\}\),对于 \((i,j)\),其权值定义为 \(a_i+b_j\)

对于常数 \(x\),按照此规则:

  • 假设一个点的权值大于等于 \(x\),那么设为 "红色"。
  • 否则设为 "蓝色"。

对于一个同色连通块,假设其触碰到了边界,那么其贡献为 \(1\),否则为 \(2\)

求红色连通块的权值和减去蓝色连通块的权值和。

多组查询,每次给定 \(x\)

\(n,m,q,a_i,b_i\le 10^5,x\le 2\times 10^5\)

Solution

对于某个 \(x\),如果一个点的权值大于等于 \(x\) 那么设为红色,否则设为蓝色,接下来对于全体红色点构成的图称为 \(G_1\),对于全体蓝色点构成的图称为 \(G_2\)

先尝试表达出两个图上的连通块的数量,由于图为平面图,根据欧拉公式:

\[V-E+F=cnt+1 \]

即点数减去边数加上面数为连通块数 \(+1\)

由于没有触碰到边界的连通块和触碰到了边界的连通块对答案的贡献不同,所以直接处理是非常麻烦的。

考虑 \(G_1\) 的每个连通块,不难发现内部一定是由若干个四连通块构成(或者不存在面)

每个四连通块都代表着一个面,设其数量为 \(f_1\),接下来通过一定的观察,我们发现 \(G_1\) 中的面除去此类四连通块和 "外面",每个面均代表着 \(G_2\) 中的一个没有碰到边界的连通块。

设没有碰到边界的连通块数量分别为 \(g_1,g_2\),那么就有 \(g_1=F_2-f_2-1,g_2=F_1-f_1-1\)

于是我们实际上想要统计的答案为:

\[cnt_1+g_1-cnt_2-g_2 \]

等价于:

\[(V_1-E_1+F_1)+(F_2-f_2)-(V_2-E_2+F_2)-(F_1-f_1) \]

(这里提前把 \(+1/-1\) 均消去了)

即:

\[(V_1-V_2)+(f_1-f_2)-(E_1-E_2) \]

于是我们最终只需要统计点数差,边数差,四连通块数量差即可。

对于某个 \(x\),点数差即有多少对 \((i,j)\) 满足 \(a_i+b_j\ge x\),这个可以通过 FFT 卷积处理 \(x=a_i+b_j\) 的点对 \((i,j)\) 数量,然后做后缀和得到结果。

对于某个 \(x\),竖着的边为红色当且仅当 \(a_i+b_j\ge x,a_{i+1}+b_j\ge x\),等价于 \(\min\{a_i,a_{i+1}\}+b_j\ge x\),也可以通过卷积处理,横着的边类似。

对于某个 \(x\),四连通块的贡献也可以类似处理\((\min(a_i,a_{i+1})+\min(b_j,b_{j+1})\ge x)\)

小于的情况就反过来即可。

复杂度为 \(\mathcal O(w\log w+q)\),其中 \(w\) 为值域,即 \(10^5\)

会附带 FFT 的本身的常数,和你需要做 \(13\) 次 FFT 的常数。

\(Code:\)

#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
#define int long long
int gi() {
	char cc = getchar() ; int cn = 0, flus = 1 ;
	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
	return cn * flus ;
}
const int N = 4e5 + 5 ; 
const double Pi = acos(-1.0) ; 
int n, m, q, limit, L, R[N], A[N], B[N] ; 
int V1[N], V2[N], E1[N], E2[N], F1[N], F2[N] ; 
struct Complex {
	double x, y ; 
	Complex(double _x = 0, double _y = 0) { x = _x, y = _y ; }
} F[N], G[N], H[N], D[N], E[N], Q[N], Ans[N], A1[N], A2[N], A3[N], A4[N], A5[N], A6[N], A7[N] ;
Complex operator + (const Complex &x, const Complex &y) { return Complex(x.x + y.x, x.y + y.y) ; }
Complex operator * (const Complex &x, const Complex &y) { return Complex(x.x * y.x - x.y * y.y, x.x * y.y + x.y * y.x) ; }
Complex operator - (const Complex &x, const Complex &y) { return Complex(x.x - y.x, x.y - y.y) ; }
void init(int x) {
	L = 0, limit = 1 ; while(limit < x) limit <<= 1, ++ L ; 
	for(re int i = 0; i < limit; ++ i) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1)) ;
}
void FFT(Complex *a, int type) {
	for(re int i = 0; i < limit; ++ i) if( R[i] > i ) swap( a[i], a[R[i]] ) ;
	for(re int k = 1; k < limit; k <<= 1) {
		Complex dw = Complex(cos(Pi / k), type * sin(Pi / k)) ;
		for(re int i = 0; i < limit; i += (k << 1) ) {
			Complex w = Complex(1, 0) ;
			for(re int j = i; j < i + k; ++ j, w = w * dw ) {
				Complex nx = a[j], ny = a[j + k] * w ;
				a[j] = nx + ny, a[j + k] = nx - ny ; 
			}
		}
	} if( type != 1 ) for(re int i = 0; i < limit; ++ i ) a[i].x = (a[i].x / (1.0 * limit) + 0.5) ; 
}
void mul(Complex *a, Complex *b, Complex *c) {
	for(re int i = 0; i < limit; ++ i) a[i] = b[i] * c[i] ; FFT(a, -1) ;
}
signed main()
{
	n = gi(), m = gi(), q = gi() ; int maxn = 1e5 ; 
	rep( i, 1, n ) A[i] = gi(), ++ F[A[i]].x, maxn = max( maxn, A[i] ) ; 
	rep( i, 1, m ) B[i] = gi(), ++ G[B[i]].x, maxn = max( maxn, B[i] ) ; 
	rep( i, 2, n ) ++ H[min(A[i], A[i - 1])].x, ++ E[max(A[i], A[i - 1])].x ;
	rep( i, 2, m ) ++ D[min(B[i], B[i - 1])].x, ++ Q[max(B[i], B[i - 1])].x ; 
	init(maxn * 2 + 3), FFT(F, 1), FFT(G, 1), FFT(H, 1), FFT(D, 1), FFT(E, 1), FFT(Q, 1) ;
	mul(A1, F, G) ; //G1 and G2 idx
	mul(A4, F, Q), mul(A5, G, E) ; //G2 edge
	mul(A2, F, D), mul(A3, G, H) ; //G1 edge 
	mul(A6, H, D) ; //four G1
	mul(A7, E, Q) ; //four G2
	rep( i, 0, limit ) 
		V1[i] = (int)(A1[i].x), V2[i] = (int)(A1[i].x),
		E1[i] = (int)(A2[i].x) + (int)(A3[i].x),
		E2[i] = (int)(A4[i].x) + (int)(A5[i].x),
		F1[i] = (int)(A6[i].x), F2[i] = (int)(A7[i].x) ; 
	drep( i, 1, limit ) V1[i - 1] += V1[i], E1[i - 1] += E1[i], F1[i - 1] += F1[i] ; 
	rep( i, 1, limit ) V2[i] += V2[i - 1], E2[i] += E2[i - 1], F2[i] += F2[i - 1] ;
	while(q--) {
		int x = gi() ; 
		int ans = V1[x] - V2[x - 1] + F1[x] - F2[x - 1] - E1[x] + E2[x - 1] ;  
		cout << ans << endl ; 
	}
	return 0 ;
}
posted @ 2020-09-12 21:48  Soulist  阅读(144)  评论(0编辑  收藏  举报