zoukankan      html  css  js  c++  java
  • Codeforces 1392I

    Codeforces 题面传送门 & 洛谷题面传送门

    模拟赛考到一道和这题有点类似的题就来补了

    神仙 GLBR I %%%%%%%%%%%%%%%%%%%%

    不过感觉见过类似的题目之后就比较套路了(?)

    首先我们记权值 (ge x) 的为黑点,(<x) 的为白点,那么我们考虑对黑点和白点分别建一张图,不妨设黑点的图为 (G_1),白点的图为 (G_2),如果相邻两个点都是黑点就在 (G_1) 中连一条边,对于白点也同理。那么显然连出来的是一张平面图,根据平面图的性质,也就是欧拉定理,如果一张平面图是连通图,那么必然有 (V-E+F=2),扩展到非连通的情况也是同理,如果一张平面图有 (x) 个连通块,那么如果我们把这 (x) 个连通块单独看作一张平面图,那么应当也有 (V_i-E_i+F_i=2),其中 (V_i,E_i,F_i) 分别为第 (i) 个连通块的点数、边数、面数。显然整张图的点数、边数分别是每个连通块的点数、边数之和,但是面数就不是这么回事了,具体来说,由于每个连通块在单独计算时都包含了外面,因此图的总面数就是所有连通块中面数减 (1) 再加 (1),即 (F=1+sumlimits_{i=1}^xF_i-1)​,而对于每个连通块,欧拉定理的式子可以变形为 (V_i-E_i+F_i-1=1),把它们加起来可以得到 (sumlimits_{i=1}^xV_i-E_i+F_i-1=x),因此对于整张图而言有 (V-E+F=x+1)

    但是我们知道,对于一张平面图而言,其面数是不好直接求的——并且就算你求得了点数、边数和面数,通过上式计算出了连通块的个数,也无法得到答案——因为本题要求的并不仅仅是连通块的个数,还要算上碰到边界的连通块的个数。因此我们还得继续考虑碰到边界的连通块个数怎么求。通过观察可以发现,对于 (G_2) 中的每一个不等于外面,且不是由某个大小为 (4) 的形如 ((x,y),(x+1,y),(x,y+1),(x+1,y+1)) 的连通块围成的面,其都对应了 (G_1) 中的一个没有碰到边界的连通块。也就是说,如果我们记 (V_1,E_1,F_1) 分别表示 (G_1) 中的点数、边数和面数,(V_2,E_2,F_2) 也同理,再记 (C_1,C_2) 分别表示 (G_1,G_2) 中形如 ((x,y),(x+1,y),(x,y+1),(x+1,y+1)) 的连通块的个数,那么可以得到 (G_1) 中碰到边界的连通块个数 (=F_2-C_2-1)(G_2) 也同理,因此我们可以得到

    [res=(V_1-E_1+F_1-1)-(V_2-E_2+F_2-1)+(F_2-C_2-1)-(F_1-C_1-1) ]

    化简一下

    [res=(V_1-V_2)-(E_1-E_2)+(C_1-C_2) ]

    这个看起来就比原问题好维护多了,我们尝试维护这东西。

    首先对于一个固定的 (x)​ 而言,(V_1)​ 的大小就是满足 (a_i+b_jge x)​ 的 ((i,j))​ 的个数,由于值域很小,可以对 (a,b)​ 分别开个桶,卷积一下求个后缀和求出 (V_1)​,对于 (E_1)​​ 我们可以将其中的边分为两类,横着的边和竖着的边,以横着的边为例,竖着的边就将式子中的 (a,b)​ 交换一下即可。显然对于两个在横方向上靠在一起的格子 ((i,j),(i,j+1))​,它们都在 (G_1)​ 中当且仅当 (a_i+b_jge x,a_i+b_{j+1}ge x),即 (a_i+max(b_j,b_{j+1})ge x),同样卷积一下即可。(C_1) 求解方法也很类似,(max(a_i,a_{i+1})+max(b_j,b_{j+1})ge x),也可以一遍卷积带走。对于 (V_2,E_2,C_2)​ 也类似,你只需要把式子中所有 (max) 换成 (min)(ge) 换成 (<) 即可。时间复杂度 (nlog n)

    const int MAXN=1e5;
    const int MAXP=1<<18;
    const double Pi=acos(-1);
    int n,m,qu,a[MAXN+5],b[MAXN+5];
    struct comp{
    	double x,y;
    	comp(double _x=0,double _y=0):x(_x),y(_y){}
    	comp operator +(const comp &rhs){return comp(x+rhs.x,y+rhs.y);}
    	comp operator -(const comp &rhs){return comp(x-rhs.x,y-rhs.y);}
    	comp operator *(const comp &rhs){return comp(x*rhs.x-y*rhs.y,x*rhs.y+y*rhs.x);}
    } A[MAXP+5],mA[MAXP+5],MA[MAXP+5],B[MAXP+5],mB[MAXP+5],MB[MAXP+5];
    comp V[MAXP+5],lV[MAXP+5],lH[MAXP+5],rV[MAXP+5],rH[MAXP+5],l4[MAXP+5],r4[MAXP+5];
    //l for <=, r for >=, V for vertical, H for horizontal, 4 for 4-connected area
    int rev[MAXP+5];
    void FFT(comp *a,int len,int type){
    	int lg=31-__builtin_clz(len);
    	for(int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
    	for(int i=0;i<len;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
    	for(int i=2;i<=len;i<<=1){
    		comp W=comp(cos(2*Pi/i),type*sin(2*Pi/i));
    		for(int j=0;j<len;j+=i){
    			comp w=comp(1,0);
    			for(int k=0;k<(i>>1);k++,w=w*W){
    				comp X=a[j+k],Y=w*a[(i>>1)+j+k];
    				a[j+k]=X+Y;a[(i>>1)+j+k]=X-Y;
    			}
    		}
    	} if(type==-1){
    		for(int i=0;i<len;i++) a[i].x=(ll)(a[i].x/len+0.5);
    	}
    }
    ll Ver_l[MAXP+5],Edg_l[MAXP+5],Fac_l[MAXP+5];
    ll Ver_r[MAXP+5],Edg_r[MAXP+5],Fac_r[MAXP+5];
    int main(){
    	scanf("%d%d%d",&n,&m,&qu);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	for(int i=1;i<=m;i++) scanf("%d",&b[i]);
    	for(int i=1;i<=n;i++) A[a[i]].x+=1;
    	for(int i=1;i<=m;i++) B[b[i]].x+=1;
    	for(int i=1;i<n;i++){
    		mA[min(a[i],a[i+1])].x+=1;
    		MA[max(a[i],a[i+1])].x+=1;
    	}
    	for(int i=1;i<m;i++){
    		mB[min(b[i],b[i+1])].x+=1;
    		MB[max(b[i],b[i+1])].x+=1;
    	}
    	FFT(A,MAXP,1);FFT(B,MAXP,1);FFT(mA,MAXP,1);FFT(mB,MAXP,1);
    	FFT(MA,MAXP,1);FFT(MB,MAXP,1);
    	for(int i=0;i<MAXP;i++){
    		V[i]=A[i]*B[i];
    		lV[i]=MA[i]*B[i];rV[i]=mA[i]*B[i];
    		lH[i]=A[i]*MB[i];rH[i]=A[i]*mB[i];
    		l4[i]=MA[i]*MB[i];r4[i]=mA[i]*mB[i];
    	} FFT(V,MAXP,-1);FFT(lV,MAXP,-1);FFT(rV,MAXP,-1);
    	FFT(lH,MAXP,-1);FFT(rH,MAXP,-1);FFT(l4,MAXP,-1);FFT(r4,MAXP,-1);
    	for(int i=1;i<=MAXP;i++){
    		Ver_l[i]+=(ll)V[i].x;Ver_r[i]+=(ll)V[i].x;
    		Edg_l[i]+=(ll)lV[i].x;Edg_r[i]+=(ll)rV[i].x;
    		Edg_l[i]+=(ll)lH[i].x;Edg_r[i]+=(ll)rH[i].x;
    		Fac_l[i]+=(ll)l4[i].x;Fac_r[i]+=(ll)r4[i].x;
    	}
    	for(int i=1;i<=MAXP;i++) Ver_l[i]+=Ver_l[i-1],Edg_l[i]+=Edg_l[i-1],Fac_l[i]+=Fac_l[i-1];
    	for(int i=MAXP;i;i--) Ver_r[i]+=Ver_r[i+1],Edg_r[i]+=Edg_r[i+1],Fac_r[i]+=Fac_r[i+1];
    	while(qu--){
    		int x;scanf("%d",&x);
    		printf("%lld
    ",(Ver_r[x]-Ver_l[x-1])-(Edg_r[x]-Edg_l[x-1])+(Fac_r[x]-Fac_l[x-1]));
    	}
    	return 0;
    }
    
  • 相关阅读:
    react:如何创建一个新项目
    python3-多重继承
    Stylus-富有表现力的、动态的、健壮的CSS
    使用@property
    python3-使用__slots__
    python:实例属性和类属性
    java_day1
    学习笔记144—SPSS 重复测量方差分析【方法二】
    学习笔记143—SPSS 重复测量的多因素方差分析
    学习笔记142—Matlab如何读取Excel和写入Excel??
  • 原文地址:https://www.cnblogs.com/ET2006/p/Codeforces-1392I.html
Copyright © 2011-2022 走看看