【题目链接】
http://uoj.ac/problem/198
https://www.lydsy.com/JudgeOnline/problem.php?id=5077
【题解】
先求出每个星球在dfs序上的对应区间,虽然有的星球不止一个区间,但区间的总数是
O(N)
O
(
N
)
级别的。然后把这些区间标记在线段树上。显然每个星球可以看做斜率优化中的一条直线,所以对于线段树上每个点,维护一个凸包,询问的时候对于每个凸包都询问一次就行了。
但这样做的时间复杂度是
O(N∗log2N)
O
(
N
∗
l
o
g
2
N
)
的,无法通过此题,考虑将询问放在一起考虑,先将询问标记在对应的叶节点上,按x轴从小到大加入询问。由于x轴递增,所以最优的星球的坐标也是单调增的。在处理非叶节点时,可以先归并排序,再进行查询。
时间复杂度
O(N∗logN)
O
(
N
∗
l
o
g
N
)
【代码】(常数有点大,在bzoj上无法通过)
/* - - - - - - - - - - - - - - -
User : VanishD
problem : [bzoj5077][ctsc2016]
Points : segment tree
- - - - - - - - - - - - - - - */
# include <bits/stdc++.h>
# define ll long long
# define inf 0x3f3f3f3f
# define N 500010
using namespace std;
int read(){
int tmp = 0, fh = 1; char ch = getchar();
while (ch < '0' || ch > '9'){ if (ch == '-') fh = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9'){ tmp = tmp * 10 + ch - '0'; ch = getchar(); }
return tmp * fh;
}
ll readll(){
ll tmp = 0, fh = 1; char ch = getchar();
while (ch < '0' || ch > '9'){ if (ch == '-') fh = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9'){ tmp = tmp * 10 + ch - '0'; ch = getchar(); }
return tmp * fh;
}
inline void ckmin(ll &x, ll y){ x = (x > y) ? y : x; }
struct Node{
int x; ll c;
}pq[N];
struct Edge{
int data, next;
}e[N * 2];
struct Tree{
int pl, pr, l, r, mid;
vector <int> num, qry;
}T[N * 2 + 11];
vector <int> tag[N];
int head[N], place, idp[N], f[N], r[N], n, m, L, R, rt, idq[N];
ll ans[N];
void build(int u, int v){
e[++place].data = v; e[place].next = head[u]; head[u] = place;
}
void dfs(int x, int fa){
idp[x] = ++place;
for (int ed = head[x]; ed != 0; ed = e[ed].next)
if (e[ed].data != fa) dfs(e[ed].data, x);
r[x] = place;
}
inline bool cmp(Node x, Node y){
return x.x < y.x || (x.x == y.x && x.c > y.c);
}
inline bool cmpf(int x, int y){
return cmp(pq[x], pq[y]);
}
inline bool cmpq(int x, int y){
return idq[x] < idq[y];
}
void create(int &p, int l, int r){
p = ++place;
T[p].l = l, T[p].r = r;
T[p].mid = (l + r) / 2;
if (l != r){
int mid = (l + r) / 2;
create(T[p].pl, l, mid);
create(T[p].pr, mid + 1, r);
}
}
inline ll sqr(ll x){return x * x; }
inline double slope(int u, int v){
Node x = pq[u], y = pq[v];
if (x.x == y.x) return -inf;
return 0.5 * (1ll * x.x * x.x - 1ll * y.x * y.x + x.c - y.c) / (x.x - y.x);
}
void extendnum(int p, int ql, int qr, int x){
if (ql == T[p].l && qr == T[p].r){
int now = T[p].num.size() - 1;
while (now >= 1 && slope(T[p].num[now], T[p].num[now - 1]) > slope(x, T[p].num[now]))
T[p].num.pop_back(), now--;
T[p].num.push_back(x);
return;
}
if (T[p].mid >= qr) extendnum(T[p].pl, ql, qr, x);
else if (T[p].mid < ql) extendnum(T[p].pr, ql, qr, x);
else extendnum(T[p].pl, ql, T[p].mid, x),
extendnum(T[p].pr, T[p].mid + 1, qr, x);
}
inline void solve(int p){
if (T[p].num.size() == 0 || T[p].qry.size() == 0) return;
register unsigned now = 0;
for (register unsigned i = 0; i < T[p].qry.size(); i++){
while (now + 1 < T[p].num.size() && idq[T[p].qry[i]] >= slope(T[p].num[now + 1], T[p].num[now])) now++;
ckmin(ans[T[p].qry[i]], sqr(idq[T[p].qry[i]] - pq[T[p].num[now]].x) + pq[T[p].num[now]].c);
}
}
void extendqry(int p, int q, int x){
if (T[p].l == T[p].r){
T[p].qry.push_back(x);
return;
}
if (T[p].mid >= q) extendqry(T[p].pl, q, x);
else extendqry(T[p].pr, q, x);
}
void query(int p){
if (T[p].l == T[p].r){
if (T[p].qry.begin() != T[p].qry.end())
sort(T[p].qry.begin(), T[p].qry.end(), cmpq);
solve(p);
return;
}
query(T[p].pl); query(T[p].pr);
int numl = T[T[p].pl].qry.size(), numr = T[T[p].pr].qry.size();
for (register int i = 1, nowl = 0, nowr = 0; i <= numl + numr; i++){
if (nowr >= numr || (nowl < numl && idq[T[T[p].pl].qry[nowl]] < idq[T[T[p].pr].qry[nowr]]))
T[p].qry.push_back(T[T[p].pl].qry[nowl++]);
else T[p].qry.push_back(T[T[p].pr].qry[nowr++]);
}
solve(p);
}
inline bool cmptag(int x, int y){
return idp[x] < idp[y];
}
int main(){
// freopen("now.in", "r", stdin);
// freopen(".out", "w", stdout);
n = read(), m = read();
pq[0].c = readll(); tag[0].push_back(1);
for (int i = 2; i <= n; i++){
int op = read(), fa, id;
if (op == 0){
fa = read() + 1; id = read();
build(i, fa), build(fa, i);
tag[id].push_back(i);
pq[id].x = read(); read(), read();
pq[id].c = readll();
}
else {
fa = read() + 1;
build(i, fa), build(fa, i);
tag[read()].push_back(i);
}
}
place = 0; dfs(1, 0); place = 0;
L = 1, R = n;
create(rt, L, R);
for (int i = 0; i <= n; i++) f[i] = i;
sort(f, f + n + 1, cmpf);
for (int t = 0; t <= n; t++){
int i = f[t];
if (tag[i].size() == 0) continue;
int nowl = idp[tag[i][0]], nowr = r[tag[i][0]];
sort(tag[i].begin(), tag[i].end(), cmptag);
for (unsigned j = 1; j < tag[i].size(); j++){
int tmpl = idp[tag[i][j]], tmpr = r[tag[i][j]];
if (nowl < tmpl) extendnum(rt, nowl, tmpl - 1, i);
nowl = tmpr + 1;
}
if (nowl <= nowr) extendnum(rt, nowl, nowr, i);
}
for (int i = 1; i <= m; i++){
int id = read() + 1;
idq[i] = read();
extendqry(rt, idp[id], i);
}
memset(ans, inf, sizeof(ans));
query(rt);
for (int i = 1; i <= m; i++)
printf("%lld\n", ans[i]);
return 0;
}