Codeforces 1392I - Kevin and Grid(平面圖的尤拉定理+FFT)
模擬賽考到一道和這題有點類似的題就來補了
神仙 GLBR I %%%%%%%%%%%%%%%%%%%%
不過感覺見過類似的題目之後就比較套路了(?)
首先我們記權值 \(\ge x\) 的為黑點,\(<x\) 的為白點,那麼我們考慮對黑點和白點分別建一張圖,不妨設黑點的圖為 \(G_1\),白點的圖為 \(G_2\),如果相鄰兩個點都是黑點就在 \(G_1\) 中連一條邊,對於白點也同理。那麼顯然連出來的是一張平面圖,根據平面圖的性質,也就是尤拉定理,如果一張平面圖是連通圖,那麼必然有 \(V-E+F=2\),擴充套件到非連通的情況也是同理,如果一張平面圖有 \(x\)
但是我們知道,對於一張平面圖而言,其面數是不好直接求的——並且就算你求得了點數、邊數和麵數,通過上式計算出了連通塊的個數,也無法得到答案——因為本題要求的並不僅僅是連通塊的個數,還要算上碰到邊界的連通塊的個數。因此我們還得繼續考慮碰到邊界的連通塊個數怎麼求。通過觀察可以發現,對於 \(G_2\) 中的每一個不等於外面,且不是由某個大小為 \(4\) 的形如 \((x,y),(x+1,y),(x,y+1),(x+1,y+1)\) 的連通塊圍成的面,其都對應了 \(G_1\) 中的一個沒有碰到邊界的連通塊。也就是說,如果我們記 \(V_1,E_1,F_1\)
化簡一下
\[res=(V_1-V_2)-(E_1-E_2)+(C_1-C_2) \]這個看起來就比原問題好維護多了,我們嘗試維護這東西。
首先對於一個固定的 \(x\) 而言,\(V_1\) 的大小就是滿足 \(a_i+b_j\ge x\) 的 \((i,j)\) 的個數,由於值域很小,可以對 \(a,b\) 分別開個桶,卷積一下求個字尾和求出 \(V_1\),對於 \(E_1\) 我們可以將其中的邊分為兩類,橫著的邊和豎著的邊,以橫著的邊為例,豎著的邊就將式子中的 \(a,b\) 交換一下即可。顯然對於兩個在橫方向上靠在一起的格子 \((i,j),(i,j+1)\),它們都在 \(G_1\) 中當且僅當 \(a_i+b_j\ge 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\) 換成 \(<\) 即可。時間複雜度 \(n\log 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\n",(Ver_r[x]-Ver_l[x-1])-(Edg_r[x]-Edg_l[x-1])+(Fac_r[x]-Fac_l[x-1]));
}
return 0;
}