http://www.elijahqi.win/archives/3943
题目背景
半人马提雷克是“我的小马驹:友谊是魔法”第四季最后两集的大反派。在“闪闪王国(上)”中,提雷克从塔他洛斯逃了出来。为了变得更加强大,他还吸取了小马们的魔法。
题目描述
提雷克的核心技能是法力吸取。这个技能可以吸收一个魔法生物的所有魔力并把它们交给施法者。
现在我们把这个问题简化,假设你有n只小马(编号从1到n)。每只小马有三种属性。
si:时间为0时这只小马拥有的法力值
mi:这只小马可以拥有的最大法力值
ri:这只小马单位时间内回复的法力值
提雷克会给出m条指令,每一条都可以被描述为3个整数:ti,li,ri。表示在时间为ti时,提雷克会从编号为li~ri的小马中吸取魔力(包括li,ri),我们会有序地给出m条指令,请你算出每一条指令之后提雷克可以吸取多少点魔力。
输入输出格式
输入格式:
第一行包含一个整数N(1 ≤ N ≤ 1e5)-小马的编号。接下来的n行每行包含三个整数Si, mi, ri(0 ≤ si ≤ mi ≤ 1e5;0 ≤ ri ≤ 1e5),表示 一只小马。
下一行包含一个整数m(1 ≤ M ≤ 1e5)-指令数。接下来的m行包含三个整数Ti, li, ri(0 ≤ ti ≤ 1e9;1 ≤ li ≤ ri ≤ N),表示提雷克的指令。所有的指令在ti递增的顺序下给出。
输出格式:
对于每一个指令,输出一行,包含一个整数:提雷克这一次一共吸收了多少魔力。
设tag表示 一个区间是否被从初始状态修改过 如果修改过 这个区间是否被完整的修改过
如果完整的修改过 那么就针对整个区间内生长时间排序 然后二分出我上一次修改到这次询问时间在哪里 然后前面的就是全部都长满的 后面就是没有长满的 那么预处理出关于m的前缀和再预处理出关于r的后缀和 回答的时候二分一下再o(1)回答即可
如果两个区间被修改成一样的需要合并标记 只有当标记不同的时候才需要下放 如果区间标记不同则需要继续分治下去做 这样复杂度可以证明是 n×log(n)2 n × l o g ( n ) 2 的 考虑每次覆盖一个区间最多把一个区间变成两个 我如果需要暴力去做这样很多段的区间的话我后面一定会把他们再合成一段的
#include
#define lc (x<<1)
#define rc (x<<1|1)
#define ll long long
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(!isdigit(ch)) {if (ch=='-')f=-1;ch=gc();}
while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
return x*f;
}
const int N=1e5+10;
const int inf=0x3f3f3f3f;
struct node1{
int s,m,r,t;
}a[N];
struct node{
vector pre,suc;vector f;vector<int> tim;
int tag;
inline void merge(const vector &a,const vector &b){
int n1=a.size(),n2=b.size();int now1=0,now2=0;
while(now1if (a[now1].telse f.push_back(b[now2]),++now2;
}
while(now1while(now20,suc1=0;
for (int i=0;i10);for (int i=f.size()-1;~i;--i) suc1+=f[i].r,suc[i]=suc1;
}
inline ll gao(int t){
t=t-tag;int p=lower_bound(tim.begin(),tim.end(),t)-tim.begin();
ll tmp=0;if (p) tmp+=pre[p-1];
if(p!=tim.size()) tmp+=(ll)suc[p]*t;return tmp;
}
}tree[N<<2];
int n,t,m;
inline void update(int x){
if (tree[lc].tag==-2||tree[rc].tag==-2) {tree[x].tag=-2;return;}
if (tree[lc].tag==tree[rc].tag&&tree[lc].tag>=0) {tree[x].tag=tree[lc].tag;return;}
tree[x].tag=-1;
}
inline void build(int x,int l,int r){
tree[x].tag=-2;
if(l==r) {
tree[x].f.push_back(a[l]);tree[x].pre.push_back(a[l].m);
tree[x].tim.push_back(a[l].t);tree[x].suc.push_back(a[l].r);return;
}int mid=l+r>>1;
build(lc,l,mid);build(rc,mid+1,r);
tree[x].merge(tree[lc].f,tree[rc].f);
}
inline void pushdown(int x){
if (tree[x].tag>=0) tree[lc].tag=tree[rc].tag=tree[x].tag;
}
inline ll query(int x,int l,int r,int l1,int r1){
if (l==r&&tree[x].tag==-2){
ll tmp=a[l].s;tmp+=(ll)t*a[l].r;tmp=min(tmp,(ll)a[l].m);
tree[x].tag=t;return tmp;
}
if (l1<=l&&r1>=r&&tree[x].tag>=0){
ll tmp=tree[x].gao(t);tree[x].tag=t;return tmp;
}
int mid=l+r>>1;pushdown(x);ll tmp=0;
if (l1<=mid) tmp+=query(lc,l,mid,l1,r1);
if (r1>mid) tmp+=query(rc,mid+1,r,l1,r1);
update(x);return tmp;
}
int main(){
freopen("cf.in","r",stdin);
n=read();
for (int i=1;i<=n;++i) {
a[i].s=read(),a[i].m=read(),a[i].r=read();
a[i].t=a[i].r?a[i].m/a[i].r:inf;
}build(1,1,n);m=read();
for (int i=1;i<=m;++i){
int l,r;t=read();l=read();r=read();
printf("%lld\n",query(1,1,n,l,r));
}
return 0;
}