[lnsyoj2115] Darko 的游戏

题意

原题链接

sol

假设图已经被建好了,那么问题就被转化为,在一个图上给定起点求走 k 步的权值为多少,倍增解决即可,接下来考虑如何建图。
分析需求,可以发现只需要求出一个数在区间内的非严格前驱和后继,再进行比较即可。
前驱和后继可以使用线段树或平衡树解决,由于可持久化平衡树很少用,因此考虑可持久化线段树解决。
对于整个序列,只需要支持查询一个数的排名和排名对应的数即可求得前驱和后继,子区间相同,只需要将权值变为两个版本的差即可。

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#define x first 
#define y second 

using namespace std;
typedef long long LL;
typedef pair<LL, int> PLI;

const int N = 500005, K = 18;

PLI ne[N][K + 5];
int n, m;
int a[N], b[N], ha[N], rk[N];
int rt[N], idx;
int l[N], r[N];

struct Node {
    int val;
    int l, r;
} tr[N << 5];

int newnode(){
    idx ++ ;
    tr[idx].l = tr[idx].r = tr[idx].val = 0;
    return idx;
}

void build(int &u, int l, int r){
    if (!u) u = newnode();
    if (l == r) return ;
    int mid = l + r >> 1;
    build(tr[u].l, l, mid), build(tr[u].r, mid + 1, r);
}

void insert(int &u, int od, int l, int r, int x){
    if (!u) u = newnode();
    tr[u] = tr[od];
    tr[u].val ++ ;
    if (l == r) return ;
    int mid = l + r >> 1;
    if (x <= mid) insert(tr[u].l = 0, tr[od].l, l, mid, x);
    else insert(tr[u].r = 0, tr[od].r, mid + 1, r, x);
}

int get_val(int u, int od, int l, int r, int k){
    if (l == r) return l;
    int s = tr[tr[u].l].val - tr[tr[od].l].val;
    // printf("?!%d %d %d %d\n", l, r, s, k);
    int mid = l + r >> 1;
    if (s >= k) return get_val(tr[u].l, tr[od].l, l, mid, k);
    else return get_val(tr[u].r, tr[od].r, mid + 1, r, k - s);
}

int get_rk(int u, int od, int l, int r, int x, int s){
    if (l == r) return s + 1;
    int ss = tr[tr[u].l].val - tr[tr[od].l].val;
    int mid = l + r >> 1;
    if (x <= mid) return get_rk(tr[u].l, tr[od].l, l, mid, x, s);
    else return get_rk(tr[u].r, tr[od].r, mid + 1, r, x, s + ss);
}

int get_prev(int l, int r, int x){
    // printf("%d %d %d %d\n", l, r, x, get_rk(rt[r], rt[l - 1], 0, n + 1, x, 0));
    return get_val(rt[r], rt[l - 1], 0, n + 1, get_rk(rt[r], rt[l - 1], 0, n + 1, x, 0) - 1);
}

int get_next(int l, int r, int x){
    return get_val(rt[r], rt[l - 1], 0, n + 1, get_rk(rt[r], rt[l - 1], 0, n + 1, x, 0));
}

void build_graph(){
    for (int i = 1; i <= n; i ++ ) ha[i] = b[i] = a[i];
    sort(ha + 1, ha + n + 1);
    for (int i = 1; i <= n; i ++ ) b[i] = lower_bound(ha + 1, ha + n + 1, b[i]) - ha, rk[b[i]] = i;

    build(rt[0], 0, n + 1);
    for (int i = 1; i <= n; i ++ ) insert(rt[i], rt[i - 1], 0, n + 1, b[i]);
    for (int i = 1; i <= n; i ++ ) {
        int p = get_prev(l[i], r[i], b[i]);
        int nx = get_next(l[i], r[i], b[i]);
        // printf("##%d %d %d %d %d\n", i, p, nx, ha[p], ha[nx]);
        int ans;
        if (!p || nx <= n && ha[nx] - a[i] < a[i] - ha[p]) ans = nx;
        else ans = p;
        int pos = rk[ans];
        ne[i][0] = {abs(ha[ans] - a[i]), pos};
    }
    // for (int i = 1; i <= n; i ++ ) {
    //     printf("!%d %d %lld\n", i, ne[i][0].y, ne[i][0].x);
    // }
}

void init(){
    for (int i = 1; i <= K; i ++ )
        for (int j = 1; j <= n; j ++ )
            ne[j][i] = {ne[j][i - 1].x + ne[ne[j][i - 1].y][i - 1].x, ne[ne[j][i - 1].y][i - 1].y};
}

LL find(int u, int k){
    LL res = 0;
    for (int i = K; i >= 0; i -- ){
        int step = 1 << i;
        if (k < step) continue;
        res += ne[u][i].x;
        u = ne[u][i].y;
        k -= step;
    }
    return res;
}

int main(){
    freopen("data1.in", "r", stdin);
    freopen("data1.out", "w", stdout);
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
    for (int i = 1; i <= n; i ++ ) scanf("%d%d", &l[i], &r[i]);
    build_graph();
    // for (int u = 1; u <= idx; u ++ ) printf("(%d %d %d) ", tr[u].l, tr[u].r, tr[u].val);
    // for (int i = 0; i < 4; i ++ ) printf("%d ", rt[i]);
    init();
    scanf("%d", &m);
    while (m -- ){
        int u, v, k;
        scanf("%d%d%d", &u, &v, &k);
        LL x = find(u, k), y = find(v, k);
        // printf("D%lld %lld\n", x, y);
        if (x > y) puts("win");
        if (x < y) puts("lose");
        if (x == y) puts("draw");
    }
}
posted @   是一只小蒟蒻呀  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示