題意:一棵 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
logn)
\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 ...