可持久化线段树 HDU4866 Shooting

题目链接 

一些平行于x轴的线段作为射击目标,每次在x轴上选一个点向y轴方向射击,可以射中最近的k个目标,得分是射中目标的高度和,求这个得分。

对高度建立函数式线段树,按顺序对x轴坐标建树,维护区间和和区间个数,每次射击询问该线段树即可。

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <vector>
#include <queue>

using namespace std;

#define  N    5522222
#define  LL   long long
#define  mod  1000000007ll
#define  inf  0XFFFFFFF
#define  pii  pair<int, int>
#define  mp   make_pair
#define  eps  1e-3
#define  euC  0.57721566490153286060651209

struct Seg {
    int cnt; LL sum;
    int l, r;
    Seg *ch[2];
} pool[N];
Seg *tot;
Seg* newNode() {
    tot->cnt = tot->sum = 0;
    tot->l = tot->r = 0;
    tot->ch[0] = tot->ch[1] = NULL;
    return tot++;
}
Seg *root[N];
Seg* buildtree(int l, int r) {
    Seg *ret = newNode();
    ret->l = l;
    ret->r = r;
    if (l == r)
        return ret;
    int mid = (l + r) / 2;
    ret->ch[0] = buildtree(l, mid);
    ret->ch[1] = buildtree(mid + 1, r);
    return ret;
}
LL H[N];
Seg* update(int w, int x, Seg *now) {
    Seg *ret = newNode();
    *ret = *now;
    if (ret->l == ret->r) {
        ret->cnt += x;
        ret->sum += H[ret->l] * x;
        return ret;
    }
    int mid = (ret->l + ret->r) / 2;
    if (w <= mid)
        ret->ch[0] = update(w, x, ret->ch[0]);
    else
        ret->ch[1] = update(w, x, ret->ch[1]);
    ret->cnt = ret->ch[0]->cnt + ret->ch[1]->cnt;
    ret->sum = ret->ch[0]->sum + ret->ch[1]->sum;
    return ret;
}
pair<int, LL> get(int l, int r, Seg *now) {
    pair<int, LL> ret;
    if (l <= now->l && now->r <= r)
        return make_pair(now->cnt, now->sum);
    int mid = (now->l + now->r) / 2;
    if (l <= mid) {
        pair<int, LL> tmp = get(l, r, now->ch[0]);
        ret.first += tmp.first;
        ret.second += tmp.second;
    }
    if (r > mid) {
        pair<int, LL> tmp = get(l, r, now->ch[1]);
        ret.first += tmp.first;
        ret.second +=tmp.second;
    }
    return ret;
}
int n, m, X;
LL P;
int x[N];
inline int read() {
    int ret;
    scanf("%d", &ret);
    return ret;
}

int Main() {
    while (scanf("%d", &n) != EOF) {
        tot = pool;
        multiset<pii> pos, neg;
        set<int> st;
        scanf("%d%d", &m, &X);
        P = read();
        for (int i = 0; i < n; i++) {
            int l, r, d;
            scanf("%d%d%d", &l, &r, &d);
            st.insert(d);
            pos.insert(mp(l, d));
            neg.insert(mp(r + 1, d));
        }
        int num = 0;
        H[++num] = 0;
        for (set<int>::iterator po = st.begin(); po != st.end(); po++) {
            H[++num] = *po;
        }
        sort(H + 1, H + num + 1);
        int all = 0;
        root[all++] = buildtree(1, num);
        while (pos.size() || neg.size()) {
            if (pos.size() && (neg.size() == 0 || pos.begin()->first <= neg.begin()->first)) {
                x[all] = pos.begin()->first;
                int rank = lower_bound(H + 1, H + num + 1, pos.begin()->second) - H;
                root[all] = update(rank, 1, root[all-1]);
                all++;
                pos.erase(pos.begin());
            } else {
                x[all] = neg.begin()->first;
                int rank = lower_bound(H + 1, H + num + 1, neg.begin()->second) - H;
                root[all] = update(rank, -1, root[all-1]);
                all++;
                neg.erase(neg.begin());
            }
        }
        LL pre = 1;
        for (int _m = 0; _m < m; _m++) {
            int xx;
            LL aa, bb, cc;
            scanf("%d", &xx);
            aa = read(); bb = read(); cc = read();
            LL kk = (aa * pre + bb) % cc;
            xx = upper_bound(x, x + all, xx) - x - 1;
            int l = 1, r = num;
            while (l < r) {
                int mid = (l + r) / 2;
                pair<int, LL> tmp = get(1, mid, root[xx]);
                if (tmp.first < kk) l = mid + 1;
                else r = mid;
            }
            pre = (pre > P) ? 2 : 1;
            pair<int, LL> tmp = get(1, l, root[xx]);
            LL bei = 0;
            if (tmp.first > kk)
                bei = tmp.first - kk;
            pre *= tmp.second - H[l] * bei;
            printf("%I64d\n", pre);
        }
    }

    return 0;
}

int main() {
    return Main();
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值