[bzoj5077][uoj198][ctsc2016]时空旅行【线段树】【dfs序】

【题目链接】
  http://uoj.ac/problem/198
  https://www.lydsy.com/JudgeOnline/problem.php?id=5077
【题解】
  先求出每个星球在dfs序上的对应区间,虽然有的星球不止一个区间,但区间的总数是 O ( N ) 级别的。然后把这些区间标记在线段树上。显然每个星球可以看做斜率优化中的一条直线,所以对于线段树上每个点,维护一个凸包,询问的时候对于每个凸包都询问一次就行了。
  但这样做的时间复杂度是 O ( N l o g 2 N ) 的,无法通过此题,考虑将询问放在一起考虑,先将询问标记在对应的叶节点上,按x轴从小到大加入询问。由于x轴递增,所以最优的星球的坐标也是单调增的。在处理非叶节点时,可以先归并排序,再进行查询。
  时间复杂度 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;
}

猜你喜欢

转载自blog.csdn.net/d_vanisher/article/details/80566542
今日推荐