zoukankan      html  css  js  c++  java
  • 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);
    	}
    }
    
  • 相关阅读:
    不同类型的磁盘存储在Ubuntu下的性能测试
    Ubuntu16.04编译安装Redis Desktop Manager
    gnu screen的用法
    MySQL Workbench常用快捷键
    Libevent例子(二)
    Libevent例子(一)
    Ubuntu下的init.d管理update-rc.d
    Centos7 修改终端文字显示颜色
    通过socks tunnel设置http代理
    linux:C++的socket编程
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14748863.html
Copyright © 2011-2022 走看看