[COGS2651]新史「新幻想史 -现代史-」-CDQ分治

新史「新幻想史 -现代史-」

题目解释:
所有整数都是正整数
新添一组大样例
题目最下面的咒语使用似乎会ce,请勿使用
已添加一句话题意
第i个时刻开始的时候会继承第i-1个时刻的状态
为了使题意更加容易理解,样例已更新

【题目描述】

慧音也想要退治妖怪!
在某次异变中,慧音要退治排成一列的n个妖怪,作为”吞食历史的半兽”,慧音会使用符卡”新史「新幻想史 -现代史-」”修改过去的历史来让一段区间内的妖怪力量减少,同时因为历史被改变了,所以会有另一段区间的妖怪力量增强(一个妖怪的力量改变后,这个效果会一直持续到后面的时刻)。为了让修改历史的效果最稳定,慧音还想知道在过去的某个时刻一段区间中所有妖怪的妖力和是多少,每个时刻慧音只会发出一条指令。
战斗持续了m个时刻,由于慧音还要集中精力发射头槌弹幕,所以她请你来帮忙解决她的询问。
(没有进行任何操作的时刻为0时刻
关于时间线的说明:
如果有以下操作:询问1->修改->询问2,询问的目标时刻相等,修改的目标时刻小于等于询问的目标时刻,则询问1不会受到修改的影响,而询问2会
如果有以下操作:询问1->修改->询问2,询问的目标时刻相等,修改的目标时刻大于询问的目标时刻,则两个询问都不会受到修改的影响
特别提醒:
比赛进行中请尽量不要进行有关时间线或世界线的伦理思考
一句话题意:
有一个长度为n的整数序列,共m个时刻,在每个时刻都有一个操作,如果是询问操作则询问指定时刻一段区间的和,如果是修改操作则使修改指定时刻到当前时刻的所有时刻一段区间全部增加一个数,另一段区间全部减少一个数

【输入格式】

第一行两个整数n,m,意义如上
接下来一行n个整数,第i个整数ai表示第i个妖怪的妖力
接下来m行,第i行表示第i个时刻的指令,首先一个字符c,如果c为’Q’,接下来三个用空格隔开的整数x,y,z,表示询问第z个时刻区间[x,y]中所有妖怪的妖力和,如果c为’M’,接下来七个整数x,y,z,l,r,v,t,表示在第t个时刻,区间[x,y]中所有妖怪的妖力减少了z,区间[l,r]中所有妖怪妖力增加了v
输入数据中一行中的所有整数和字符用空格隔开

【输出格式】

对于每个M操作,输出一行一个值表示查询的结果

【样例输入1】

5 5
1 2 3 4 5
Q 1 3 0
M 1 2 1 2 3 2 1
Q 1 3 0
Q 1 3 1
Q 1 3 3

【样例输出1】

6
6
8
8

【样例输入2】

12 12
20755 32646 15599 16925 29509 29411 31544 19290 25477 30085 4973 21417
M 8 11 32373 4 7 2615 1
Q 7 7 0
M 8 10 32317 12 12 1710 3
M 4 5 28846 2 7 6548 4
Q 9 11 4
Q 12 12 4
Q 5 11 2
M 6 10 32331 6 7 1272 8
M 2 11 17117 4 9 19679 9
M 4 5 21667 4 5 13394 5
M 8 10 11508 9 11 30783 11
Q 8 9 6

【样例输出2】

31544
-101218
23127
48642
-84613

【样例解释】

第1个时刻,慧音询问第0个时刻[1,3]这个区间的妖力和,显然答案为6
第2个时刻,慧音使第1个时刻[1,2]的妖力减少1,[2,3]的妖力增加2
现在第1个时刻和第2个时刻的妖力序列都是0 3 5 4 5,而第0个时刻的妖力序列依旧是1 2 3 4 5
之后的两次询问就是在第0个时刻[1,3]的妖力和和第1个时刻[1,3]的妖力和,显然答案分别为6和8

【数据范围】

n,m<=50000,ai,v,z<=10^5
对于所有数据,保证查询和修改的目标时刻在进行操作的时刻或进行操作的时刻之前;数据有梯度


《论根据名字选择题目的优越性3》
貌似以车万为题面的题目质量都挺高的…..
过气车万


思路:
连咱这种几乎不写CDQ的蒟蒻都能一眼看出是CDQ的题目……

首先,把修改拆成4份,询问拆成两份,采用前缀和形式,如[l,r]区间+1拆成l-1处-1,r处+1
(其实不拆也可以然而拆了更好写)
考虑初始根据操作顺序排序,然后对所有操作按照时刻分治。
然后按惯例用左区间的修改更新右区间的询问即可~

最后后可以考虑维护一个兹瓷区间加和区间查询的数据结构。
这里用的是树状数组~

话说树状数组就是快啊,靠着树状数组上榜了~

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>

using namespace std;

typedef long long ll;

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0' || '9'<ch){if(ch=='-')f=-1;ch=getchar();}
    while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
    return x;
}

const int N=50009*4;

struct item
{
    int ty,id,t,pos,val,ansid;
    bool operator < (item o)
    {
        if(t==o.t)return ty>o.ty;
        return t<o.t;
    }
}q[N],tmpq[N];

int n,m,tot,anscnt;
ll bits[2][N],ans[N],a[N],sum[N];

inline int lolbit(int x){return x&(-x);}
inline void add(ll *bit,int x,ll v)
{
    for(;x<=n;x+=lolbit(x))
        bit[x]+=v;
}

inline ll query(ll *bit,int x)
{
    ll ret=0;
    for(;x;x-=lolbit(x))
        ret+=bit[x];
    return ret;
}

inline void adds(int x,ll v)
{
    add(bits[0],1,v);
    add(bits[0],x+1,-v);
    add(bits[1],x+1,-x*v);
}

inline ll querys(int x)
{
    return x*query(bits[0],x)-query(bits[1],x);
}

inline void solve(int l,int r)
{
    if(l==r)
        return;

    int mid=l+r>>1;
    solve(l,mid);
    solve(mid+1,r);

    int pl=l,pr=mid+1,top=l-1;
    while(pl<=mid && pr<=r)
    {
        if(q[pl]<q[pr])
        {
            if(q[pl].ty)
                adds(q[pl].pos,q[pl].val);
            tmpq[++top]=q[pl++];
        }
        else
        {
            if(!q[pr].ty)
                ans[q[pr].ansid]+=q[pr].val*querys(q[pr].pos);
            tmpq[++top]=q[pr++];
        }
    }

    while(pl<=mid)
    {
        if(q[pl].ty)
            adds(q[pl].pos,q[pl].val);
        tmpq[++top]=q[pl++];
    }
    while(pr<=r)
    {
        if(!q[pr].ty)
            ans[q[pr].ansid]+=q[pr].val*querys(q[pr].pos);
        tmpq[++top]=q[pr++];
    }

    for(int i=l;i<=mid;i++)
        if(q[i].ty)
            adds(q[i].pos,-q[i].val);

    for(int i=l;i<=r;i++)
        q[i]=tmpq[i];
}

int main()
{
    freopen("cdcq_a.in","r",stdin);
    freopen("cdcq_a.out","w",stdout);

    n=read();m=read();

    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        sum[i]=sum[i-1]+a[i];
    }
    for(int i=1;i<=m;i++)
    {
        char c[10];
        scanf("%s",c);
        if(c[0]=='Q')
        {
            int l=read(),r=read(),t=read();
            q[++tot]=(item){0,tot,t,l-1,-1,++anscnt};
            q[++tot]=(item){0,tot,t,r,1,anscnt};
            ans[anscnt]=sum[r]-sum[l-1];
        }
        else
        {
            int x=read(),y=read(),z=read(),l=read(),r=read(),d=read(),t=read();
            q[++tot]=(item){1,tot,t,x-1,z,0};
            q[++tot]=(item){1,tot,t,y,-z,0};
            q[++tot]=(item){1,tot,t,r,d,0};
            q[++tot]=(item){1,tot,t,l-1,-d,0};
        }
    }

    solve(1,tot);

    for(int i=1;i<=anscnt;i++)
        printf("%lld\n",ans[i]);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值