zoukankan      html  css  js  c++  java
  • CF1392I

    CF1392I

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

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

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

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

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

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

    (n,m,q,a_i,b_ile 10^5,xle 2 imes 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_jge x),这个可以通过 FFT 卷积处理 (x=a_i+b_j) 的点对 ((i,j)) 数量,然后做后缀和得到结果。

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

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

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

    复杂度为 (mathcal O(wlog 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 ;
    }
    
  • 相关阅读:
    好学习法
    error execution phase upload-config/kubelet: Error writing Crisocket information for the control-plane node: timed out waiting for the condition
    linux 大实话
    解决vi/vim中粘贴 格式错乱
    centos7 调试系统服务命令
    gitlab jenkins docker kubernetes
    修改centos7主机名
    野战ci/cd
    相互交流生成快捷网页链接
    设置centos7静态网卡配置文件
  • 原文地址:https://www.cnblogs.com/Soulist/p/13658837.html
Copyright © 2011-2022 走看看