[cf453e]Little Pony and Lord Tirek

来自FallDream的博客,未经允许,请勿转载,谢谢。


更博客= =

有n个数,每个数字都有一个初始大小ai和最大值mi,然后每秒会增加ri,你需要回答m个发生时间依此增大的询问,每次询问区间和并且将区间的所有数字变成0.

n,m<=10^5

考虑直接用set维护颜色段,这样操作到的段数是O(n)的。然后特殊处理开始的情况,就变成了若干个询问,每次询问一个区间的数全部从0开始,一定时间之后的和。

将这些询问排序,并且将所有数字到达最大值的时间排序,用两棵线段树来模拟就行了,复杂度O(nlogn)

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<set>
#define MN 100000
#define N 131072
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct data{int l,r,t,x;
    data(int _l,int _r,int _t,int _x){l=_l;r=_r;t=_t;x=_x;}
    data(int k){l=k;r=0;}
    bool operator <(const data&b)const{return l==b.l?r<b.r:l<b.l;}
};
set<data> s;long long Ans[MN+5],T1[N*2+5],T2[N*2+5];
int n,m,top,a[MN+5],mx[MN+5],R[MN+5],rk[MN+5],tms[MN+5];
struct ques{int l,r,t,id;}q[MN*10+5];
int Calc(int t,int x,int r,int m){return (int)min((long long)m,x+1LL*r*t);}
bool cmp(const ques&a,const ques&b){return a.t<b.t;}
bool cmp2(int x,int y){return tms[x]<tms[y];}
void Renew(long long*T,int x,int v){for(T[x+=N]+=v;x>>=1;)T[x]=T[x<<1]+T[x<<1|1];}
long long Query(long long*T,int l,int r)
{
    long long sum=0;
    for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1) sum+=T[l+1];
        if( r&1) sum+=T[r-1];
    }    
    return sum;
}
int main()
{
    n=read();
    for(int i=1;i<=n;++i)
    {
        a[i]=read();mx[i]=read();R[i]=read();tms[i]=R[i]?(int)ceil((double)mx[i]/R[i]):2e9;
        s.insert(data(i,i,0,a[i]));    rk[i]=i;
    }
    m=read();
    for(int i=1;i<=m;++i)
    {
        int t=read(),l=read(),r=read();
        set<data>::iterator it=s.lower_bound(data(l));    
        for(;it!=s.end()&&it->l<=r;it=s.lower_bound(data(l)))
        {
            if(it->r>r) s.insert(data(r+1,it->r,it->t,it->x));
            if(it->r==it->l) Ans[i]+=Calc(t-it->t,it->x,R[it->r],mx[it->r]);
            else q[++top]=(ques){it->l,min(it->r,r),t-it->t,i};
            s.erase(it);
        }
        for(;it!=s.begin()&&(--it)->r>=l;it=s.lower_bound(data(l)))
        {
            if(it->r>r) s.insert(data(r+1,it->r,it->t,it->x));
            if(it->l<l) s.insert(data(it->l,l-1,it->t,it->x));
            q[++top]=(ques){max(it->l,l),min(r,it->r),t-it->t,i};
            s.erase(it);
        }    
        s.insert(data(l,r,t,0));
    }
    sort(rk+1,rk+n+1,cmp2);
    sort(q+1,q+top+1,cmp);
    for(int i=1;i<=n;++i) Renew(T1,i,R[i]);
    for(int i=1,j=1;i<=top;)
        if(j<=n&&tms[rk[j]]<=q[i].t)
        {
            Renew(T1,rk[j],-R[rk[j]]);
            Renew(T2,rk[j],mx[rk[j]]);    
            ++j;
        }
        else 
        {
            Ans[q[i].id]+=1LL*q[i].t*Query(T1,q[i].l,q[i].r)+Query(T2,q[i].l,q[i].r);
            ++i;
        }
    for(int i=1;i<=m;++i) printf("%lld\n",Ans[i]);
    return 0;
}

 

转载于:https://www.cnblogs.com/FallDream/p/cf453e.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值