洛谷P5114 八月臉 邊分治 閔可夫斯基和

2021-10-13 02:20:51 字數 3838 閱讀 3373

題意:一棵 n

nn 個點的樹,每個點有兩個權值 ai,

bi

a_i,b_i

ai​,bi

​,有黑白兩種顏色。m

mm 次詢問,每次給定乙個 k

kk,求一條端點異色的路徑,使得 k∑a

i+∑b

ik\sum a_i+\sum b_i

k∑ai​+

∑bi​

最大化。

n ≤2

×105

n\leq 2\times 10^5

n≤2×10

5就差把「請在邊分治的時候維護閔可夫斯基和」寫題面上了……

直觀來看是把 (ai

,bi)

(a_i,b_i)

(ai​,b

i​) 看成直線,但是並不好維護。不過半平面交和凸包是對偶的,並且凸包合併有閔可夫斯基和這個東西,所以可以把每個結點直接看成點維護凸包,詢問的時候二分就可以了。

分治的時候對兩邊黑白分別求出凸殼,然後交叉合併,把點丟到答案集合裡最後再做乙個凸包就可以了。

然後就是三度化後處理答案的問題。把新建的虛點的引數從父親那裡複製,然後如果路徑的 lca 是虛點強行給它加上去。可以在 dfs 的時候記乙個當前走的方向,然後如果是往上走的可以進行一次換方向,並在這裡統計當前點是否需要有貢獻。

複雜度 o(n

log⁡n)

\omicron(n\log n)

o(nlogn)

#include

#include

#include

#include

#include

#include

#define maxn 200005

#define maxm 400005

using

namespace std;

const

int inf=

0x7fffffff

;inline

intread()

typedef

long

long ll;

struct point};

inline point operator+(

const point& a,

const point& b)

inline point operator-(

const point& a,

const point& b)

inline ll operator*(

const point& a,

const point& b)

inline

bool

operator

<

(const point& a,

const point& b)

typedef vector hull;

#define s(t) ((int)(t).size())

void

make_hull

(hull& a)

a=t;

}void

merge

(const hull& a,

const hull& b,hull& c)

while

(i<

s(a)-1

) ans.

push_back

(a[i+1]

-a[i]),

++i;

while

(j<

s(b)-1

) ans.

push_back

(b[j+1]

-b[j]),

++j;

point las=a[0]

+b[0];

c.push_back

(las)

;for

(int i=

0;i<

s(ans)

;i++

) c.

push_back

(las=las+ans[i]);

}vector<

int> e[maxn]

;struct edgee[maxm]

;int head[maxn]

,nxt[maxm]

,cnt=1;

inline

void

addnode

(int u,

int v)

; nxt[cnt]

=head[u]

; head[u]

=cnt;

}point val[maxn]

;int vis[maxn]

,dep[maxn]

,type[maxn]

,n,tot;

void

dfs(

int u)

int cur[2]

=,pos=0;

addnode

(u,cur[0]

),addnode

(cur[0]

,u);

addnode

(u,cur[1]

),addnode

(cur[1]

,u);

val[cur[0]

]=val[cur[1]

]=val[u]

; type[cur[0]

]=type[cur[1]

]=type[u]

; dep[cur[0]

]=dep[cur[1]

]=dep[u]+1

;for

(int i=

0;i<

(int

)e[u]

.size()

;i++)if

(!vis[e[u]

[i]]

) e[cur[pos^=1

]].push_back

(e[u]

[i])

;dfs

(cur[0]

),dfs(cur[1]

);}int tp;

int rt,mn,siz[maxn]

;void

findrt

(int u,

int f,

int sum)

}hull a[2]

,b[2

],lis;

void

dfs(

int u,

int f,point cur,hull* a,

bool up)

}void

calc()

void

solve

(int sum)

intmain()

dep[1]

=1,dfs(1

);memset

(vis,0,

sizeof

(vis));

mn=inf,

findrt(1

,0,tot)

,solve

(tot)

;make_hull

(lis)

;// for (int i=0;i<(int)lis.size();i++) printf("%d %d\n",lis[i].x,lis[i].y);

lis.

push_back

(point

(lis.

back()

.x,-inf));

while

(m--

)printf

("%lld\n"

,(ll)k*lis[l]

.x+lis[l]

.y);

}return0;

}

洛谷 P1219 八皇后

題目描述 檢查乙個如下的6 x 6的跳棋棋盤,有六個棋子被放置在棋盤上,使得每行 每列有且只有乙個,每條對角線 包括兩條主對角線的所有平行線 上至多有乙個棋子。上面的布局可以用序列2 4 6 1 3 5來描述,第i個數字表示在第i行的相應位置有乙個棋子,如下 行號 1 2 3 4 5 6 列號 2 ...

洛谷 P1219 八皇后

題目描述 檢查乙個如下的6 x 6的跳棋棋盤,有六個棋子被放置在棋盤上,使得每行 每列有且只有乙個,每條對角線 包括兩條主對角線的所有平行線 上至多有乙個棋子。上面的布局可以用序列2 4 6 1 3 5來描述,第i個數字表示在第i行的相應位置有乙個棋子,如下 行號 1 2 3 4 5 6 列號 2 ...

洛谷p1219 八皇后

題目描述 檢查乙個如下的6 x 6的跳棋棋盤,有六個棋子被放置在棋盤上,使得每行 每列有且只有乙個,每條對角線 包括兩條主對角線的所有平行線 上至多有乙個棋子。上面的布局可以用序列2 4 6 1 3 5來描述,第i個數字表示在第i行的相應位置有乙個棋子,如下 行號 1 2 3 4 5 6 列號 2 ...