hiho 1034 毁灭者问题(treap)

因为有m[i]的限制,不能用 线段树搞。考虑每个魔法单位,因为d = m[i] / r[i]是固定的,当一段时间间隔 t 大于d时,答案加上m[i],否则就是t * r[i],所以变成考虑怎么维护每个魔法单位的所有时间间隔t。
离线所有操作,保存在a 和 b数组里面,a 按照 l 排序,b 按照 r 排序,L指针是a数组的,R指针是b数组的。从左到右枚举每个魔法单位,用treap维护时间间隔。插入删除的时候注意。另外还要注意r[i] == 0的情况(RE了好多发 -_-|| )
这里

#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

using namespace std;

#pragma comment(linxer, "/STACK:102400000,102400000")
#define LL long long 
#define pii pair<int, int>
#define MP make_pair
#define ls i << 1
#define rs ls | 1
#define md (ll + rr >> 1)
#define lson ll, md, ls
#define rson md + 1, rr, rs
#define mod 1000000007
#define inf 0x3f3f3f3f
#define N 2000010
#define M 200020

int getint(){
    char c = getchar(); int ret = 0;
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') ret = ret*10 + c - '0', c = getchar();
    return ret;
}
struct node{
    int t, l, r, id;
    void input(){
        t = getint(); l = getint(); r = getint();
    }
};
bool cmp1(const node &a, const node &b){
    return a.l < b.l || (a.l == b.l && a.r < b.r);
}
bool cmp2(const node &a, const node &b){
    return a.r < b.r || (a.r == b.r && a.l < b.l);
}

node a[M], b[M];
int ch[N][2], rand_val[N], sz[N], key[N], tot;
LL sum[N];
int s[M], mi[M], r[M];
set<pii > S;
set<pii >::iterator it, itt;
queue<int> q;

int creat(int val){
    tot = q.front(); q.pop();
    ch[tot][0] = ch[tot][1] = 0;
    rand_val[tot] = rand();
    key[tot] = val;
    sum[tot] = val;
    sz[tot] = 1;
    return tot;
}
int cmp(int x, int val){
    if(key[x] == val) return -1;
    return val < key[x] ? 0 : 1;
}
void push_up(int x){
    sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
    sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + key[x];
}
void rot(int &x, int d){
    int k = ch[x][!d];
    ch[x][!d] = ch[k][d];
    ch[k][d] = x;
    push_up(x);
    push_up(k);
    x = k;
}
void insert(int &x, int val){
    if(x == 0){
        x = creat(val);
        return ;
    }
    int d = cmp(x, val);
    if(d == -1)
        d = 1;
    insert(ch[x][d], val);
    if(rand_val[ch[x][d]] > rand_val[x]) rot(x, d ^ 1);
    push_up(x);
}
void del(int &x, int val) {
    if(x == 0) return;
    int d = cmp(x, val);
    if(d == -1) {
        if(!ch[x][0]) q.push(x), x = ch[x][1];
        else if(!ch[x][1]) q.push(x), x = ch[x][0];
        else {
            int d2 = rand_val[ch[x][0]] > rand_val[ch[x][1]]? 1: 0;
            rot(x, d2);
            del(ch[x][d2], val);
        }
    }
    else del(ch[x][d], val);
    if(x) push_up(x);
}
LL query1(int x, int val){        //查询小于等于val的sum值
    if(!x) return 0;
    int d = cmp(x, val);
    if(d == 0)
        return query1(ch[x][0], val);
    else
        return sum[ch[x][0]] + key[x] + query1(ch[x][1], val);
}
int query2(int x, int val){       //查询大于val的sz值
    if(!x) return 0;
    int d = cmp(x, val);
    if(d == 0)
        return sz[ch[x][1]] + 1 + query2(ch[x][0], val);
    else
        return query2(ch[x][1], val);
}
void output(int x){
    if(!x) return ;
    output(ch[x][0]);
    printf("%d ", key[x]);
    output(ch[x][1]);
}
int main(){
    for(int i = 1; i < N; ++i)
        q.push(i);
    int n;
    n = getint();
    for(int i = 1; i <= n; ++i){
        s[i] = getint(), mi[i] = getint(), r[i] = getint();
    }
    int m, pre = 0;
    m = getint();
    for(int i = 1; i <= m; ++i){
        a[i].input();
        a[i].id = i;
        pre = a[i].t;
        b[i] = a[i];
    }
    sort(a + 1, a + 1 + m, cmp1);
    sort(b + 1, b + 1 + m, cmp2);
    int L = 1, R = 1, rt = 0;
    LL ans = 0;
    S.insert(MP(0, 0));
    for(int i = 1; i <= n; ++i){
    //  if(i == n){
    //      output(rt); puts("");
    //  }
        while(L <= m && a[L].l <= i){
            it = S.lower_bound(MP(a[L].t, a[L].id));
            itt = it;
            --it;
            if(itt != S.end()){
                int tmp = (*itt).first - (*it).first;
                del(rt, tmp);
                insert(rt, (*itt).first - a[L].t);
            }
            insert(rt, a[L].t - (*it).first);
            S.insert(MP(a[L].t, a[L].id));
            L++;
        }
        while(R <= m && b[R].r < i){
            itt = S.lower_bound(MP(b[R].t, b[R].id));
            it = itt;
            ++itt;
            --it;
            if(itt == S.end()){
                del(rt, b[R].t - (*it).first);
                S.erase(MP(b[R].t, b[R].id));
                R++; 
                continue;
            }
            else{
                del(rt, (*itt).first - b[R].t);
                del(rt, b[R].t - (*it).first);
                insert(rt, (*itt).first - (*it).first);
            }
            S.erase(MP(b[R].t, b[R].id));
            R++;
        }
        int tmp = -1;
        if(S.size() > 1){
            it = S.begin();
            ++it;
            tmp = (*it).first;
            ans += min((LL)mi[i], 1LL * tmp * r[i] + s[i]);
            del(rt, tmp);
            if(r[i] > 0)
                ans += 1LL * query1(rt, mi[i] / r[i]) * r[i] + 1LL * query2(rt, mi[i] / r[i]) * mi[i];
            insert(rt, tmp);
        }
    }
    printf("%lld\n", ans);
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值