[CF 297E]Mystic Carvings解題報告

題意

有一塊圓形浮冰,其邊緣上有2n(n<=10^5)個頂點。這些頂點兩兩配對,共n對,每對頂點之間有曲線相連(可以理解爲冰面上的紋路)。有6只熊,它們是3對情侶,要選擇6個頂點打洞。要求:
①每對情侶打的兩個洞必須是配對頂點,中間有曲線連接。
②每對情侶之間的距離相等。x和y的“距離”是指,沿着浮冰邊緣從x走到y,最少需要經過的熊洞數量+1。
例如:

左邊這張圖可以,右邊這張圖不行。
圖中,1~16爲頂點,線代表配對的頂點,AB是一對情侶,CD是一對,EF是一對。
左邊圖中,C到D的距離爲1(經過0個熊洞),A到B的距離爲2,E到F的距離爲2,故不行。右圖中,A到B,C到D,E到F的距離都是1,可行。
求總的打洞方案數。如果兩個方案中打洞的集合相同,就認爲這兩個方案相同(並不考慮哪個洞是誰的)。

分析

這道題的抽象模型頗爲有趣。可以發現,只有如下兩種可能:

第一種是三對熊洞的連線兩兩交叉,第二種是三對熊洞的連線兩兩均不交叉。

如果把每條曲線對應成一個點,若兩條曲線交叉則在所對應的兩點間連紅邊,否則連藍邊,那麼我們就得到了一個含n個節點的完全圖G。可以發現,第一種方案對應G中的一個紅色三角形,第二種方案對應G中的一個藍色三角形。

我們現在試圖去求G中的純色三角形個數a。“純色三角形”並不好求,但可以將問題轉化爲求“非純色三角形”的個數b,而三角形共有C(n,3)個,所以純色三角形個數就是C(n,3)-b。

那怎麼算“非純色三角形”個數呢?可以看到,每個“非純色三角形”必然有兩個“異色角”。“異色角”是指一個角的兩條邊一紅一藍,如圖:

左邊的角就是一個異色角。黑邊的顏色未定。若爲紅,則下面的角是異色角,若爲藍,則上面的角是異色角。總之一定有兩個異色角。

於是現在只需要計算異色角的個數c,則b=c/2,a=C(n,3)-c/2.

怎麼計算呢?

假設第i條曲線連接了li和ri兩個點(li<=ri)。假設有pi條曲線和它交叉(即連出了pi條紅邊),那麼就有qi=n-1-pi條曲線和它不交叉(即連出qi條藍邊),則G中以它爲頂點的異色角個數就是pi*qi。

這pi條和它交叉的曲線都滿足:一端在區間[li,ri]內,一端在區間[li,ri]之外。不妨稱之爲“和區間[li,ri]交叉”。假設我們知道了pi,那我們就能O(1)計算出有多少條曲線和[li-1,ri]交叉(討論li-1配對點是否在區間內即可),同理也能計算出和[li+1,ri],[li,ri-1],[li,ri+1]交叉的曲線數量。

因此我們可以用分塊莫隊算法求出所有pi和qi,這樣我們就算出了異色角個數c,從而算出純色三角形個數a。

但是到此並未結束,因爲“純色三角形”還包含這種情況:


中間那對熊之間的距離是2,兩邊兩對熊之間的距離都是1,不合法。

這種情況對應於一個藍色三角形,但並不合法,需要減掉。

計算這種方案數的方法也簡單:在分塊莫隊時再計算一個值si:兩端點都在[li,ri]內(顯然不與區間[li,ri]交叉)的曲線數量(包含(li,ri)本身)。那麼,兩端點都在[li,ri]外,不與[li,ri]交叉的曲線數自然就是ti=n-si-pi,以[li,ri]爲上圖中紅線的方案數量爲(si-1)*ti。(之所以-1是要扣掉(li,ri)這條曲線)。

設這種方案數爲d,那麼總的答案就是a-d。

這樣就完美解決了問題。

代碼

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
const int SIZE=200010;
LL N,Bsize;
int match[SIZE];
class Curve{
public:
	int l,r;
};
bool operator < (const Curve &a,const Curve &b){
	if(a.l/Bsize==b.l/Bsize) return a.r<b.r;
	return a.l/Bsize<b.l/Bsize;
}
Curve C[SIZE];
LL nowl=1,nowr=0,now_cross=0,now_inner=0;
void try_add(int k){
	if(nowl<=match[k]&&match[k]<=nowr) now_inner++,now_cross--;
	else now_cross++;
}
void try_del(int k){
	if(nowl<=match[k]&&match[k]<=nowr) now_inner--,now_cross++;
	else now_cross--;
}
void work(void){
	LL all_tri=N*(N-1)*(N-2)/6;
	LL diff_cnt=0;//異色角的數量
	LL wrong_pure=0;//不合法的純色三角形數目
	for(int i=1;i<=N;i++){
		while(nowl>C[i].l) try_add(--nowl);
		while(nowr<C[i].r) try_add(++nowr);
		while(nowl<C[i].l) try_del(nowl++);
		while(nowr>C[i].r) try_del(nowr--);
		diff_cnt+=now_cross*(N-1-now_cross);
		wrong_pure+=(now_inner-1)*(N-now_inner-now_cross);
	}
	LL tri_cnt=all_tri-diff_cnt/2;//純色三角形數目
	tri_cnt-=wrong_pure;
	cout<<tri_cnt<<endl;
}
void init(void){
	cin>>N;
	Bsize=sqrt(2*N+1.0);
	int a,b;
	for(int i=1;i<=N;i++){
		scanf("%d%d",&a,&b);
		if(a>b) swap(a,b);
		C[i]=(Curve){a,b};
		match[a]=b;match[b]=a;
	}
	sort(C+1,C+1+N);
}
int main(){
	//freopen("t1.in","r",stdin);
	init();
	work();
	return 0;
}

最後貼張圖:



熊:我萌嗎?

(大聲告訴我,圖中坦克有幾對負重輪?)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章