bzoj 4071傳送門
首先算出能提前算的貢獻
$k=1$:肯定選中間的點,小學數學
$k=2$:對於每對$(x,y)$一定選離$(x+y)/2$近的橋
也就是說將$(x,y)$按$(x+y)/2$的值排序後一定恰有乙個分割點使得兩邊選擇不同的橋!
考慮如何如何快速列舉所有分割點時的答案:
需要支援插入、刪除、求中位數及兩邊的和,明顯選擇$splay$來維護(求和更容易些)
這樣先將所有數對加進乙個$splay$,再不斷將其中的數移向另一棵$splay$即可
注意:可能以前的$splay$板子容易出不少鍋啊……
首先$update$時最好對$z$進行判斷,然後$splay$最後也要$pushup$否則會在樹高低時不更新$size$
#include usingnamespace
std;
#define x first
#define y secondtypedef
double
db;typedef
long
long
ll;typedef pair
p;const
int maxn=2e5+10;//
注意範圍
const ll inf=1
<<30
;struct
splay
void rotate(int
x)
void splay(int x,int
up)
if(!up) rt=x;
//!!!!!!!!
update(x);//
可能f[x]=up,但也要update
}
void insert(int
x)
splay(k,0);
}void find(int
x)
int kth(int
x)
}//不用加邊界的刪除法
void del(int
x)
else
//由於後面沒有splay了要update
update(rt);
}ll query()
}s1,s2;
char a[10],b[10
];ll res=1ll<<60
,pre;
intn,x,y,k,tot;p dat[maxn];
bool cmp(p a,p b);
intmain()
//注意特判!!!
if(!tot) return printf("
%lld
",pre),0
; sort(dat+1,dat+tot+1
,cmp);
for(int i=1;i<=tot;i++)
s1.insert(dat[i].x),s1.insert(dat[i].y);
if(k==1) return printf("
%lld
",s1.query()+pre),0
;
for(int i=1;i<=tot;i++)
printf(
"%lld
",res+pre);
return0;
}
BZOJ4071 八鄰旁之橋(線段樹)
bzoj許可權題,洛谷鏈結 既然 k 2 那麼,突破口就在這裡 分類討論 k 1 這。不就是中位數嗎。直接把所有起點重點排個序,算下中位數就行啦 k 2 似乎不好搞了 orz zsy dalao 我太弱了 我就是乙個vegetable chicken zsy看一眼就會做 所以 define brig...
4071 Apio2015 巴鄰旁之橋
一條東西走向的穆西河將巴鄰旁市一分為二,分割成了區域 a 和區域 b。每一塊區域沿著河岸都建了恰好 1000000001 棟的建築,每條岸邊的建築都從 0 編號到 1000000000。相鄰的每對建築相隔 1 個單位距離,河的寬度也是 1 個單位長度。區域 a 中的 i 號建築物恰好與區域 b 中的...
BZOJ4071 Apio2015 巴鄰旁之橋
首先對於家和公司在同一側的預處理掉,這樣就只剩家和公司不在同一側的情況了。if k 1 ans abs x pos abs y pos 注意到與x,y是否在兩側無關,所以用經典的中位數處理思想sort一遍取中位數貪心即可。else 好久不寫splay,練習了一發 include include in...