因为有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;
}