Rip Van Winkle's Code


题目描述:

线段树操作.有两种不同的操作,a.一个是将l到r的加上一个等差数列.b.另一个是把l到r的数都改成x.查询是查询l到r的和.

题解:

两个标签的线段树,关键是要确定标签的先后顺序.我们定的是先b再a.就是说:如果有b和a的标签同时都有的话,那么我的顺序是先处理b,再处理a.如果一个点什么都没有,那么就随便加标签,如果有a标签,再加b标签,我会先把a标签传下去,再加b标签.如果现有b标签,我加a标签就加了.不会影响. 查询的时候,同时有a和b的话,先传递下去b,然后再传递下去a.

重点:

定义好标签的先后顺序

代码:
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
#define lson l,m,k<<1
#define rson m+1,r,k<<1|1
typedef long long ll;
const int N = 250010;
struct T
{
    ll st,d,s;
    int tagtag,sttag;
    ll tag;
    ll sum;
}f[N<<2];
int n;
void put(int k,ll sst,ll dd)
{
    f[k].sum += (sst + (f[k].s - 1) * dd + sst) * f[k].s / 2;
}
void down(int k)
{
    if (f[k].tagtag > 0)
    {
        f[k<<1].tag = f[k<<1|1].tag = f[k].tag;
        f[k<<1].tagtag = f[k<<1|1].tagtag = 1;

        f[k<<1].st = f[k<<1].d = f[k<<1].sttag = 0;
        f[k<<1|1].st = f[k<<1|1].d = f[k<<1|1].sttag = 0;

        f[k<<1].sum = f[k<<1].s * f[k<<1].tag;
        f[k<<1|1].sum = f[k<<1|1].s * f[k<<1|1].tag;

        f[k].tagtag = f[k].tag = 0;
    }
    if (f[k].sttag > 0)
    {
        if (f[k<<1].tagtag)
        {
            //f[k<<1].st += f[k<<1].tag;
            //f[k<<1].tagtag = f[k<<1].tag = 0;
        }
        f[k<<1].st += f[k].st; f[k<<1].d += f[k].d;
        put(k<<1,f[k].st,f[k].d);

        if (f[k<<1|1].tagtag)
        {
            //f[k<<1|1].st += f[k<<1|1].tag;
            //f[k<<1|1].tagtag = f[k<<1|1].tag = 0;
        }
        f[k<<1|1].st += f[k].st + f[k].d * f[k<<1].s; f[k<<1|1].d += f[k].d;
        put(k<<1|1,f[k].st + f[k].d * f[k<<1].s,f[k].d);

        f[k].st = f[k].d = f[k].sttag = 0;
        f[k<<1].sttag = f[k<<1|1].sttag = 1;
    }
}
void up(int k)
{
    f[k].sum = f[k<<1].sum + f[k<<1|1].sum;

}
void mk(int l,int r,int k)
{
    f[k].s = r - l + 1;
    f[k].sttag = 0;
    f[k].tagtag = f[k].sum = f[k].tag = f[k].st = f[k].d = 0;
    if (l == r)
    {
        return;
    }
    int m = (l + r) >> 1;
    mk(lson);
    mk(rson);
    //up(k);
}
void update1(int la,int ra,int l,int r,int k,ll st,ll d)
{
    if (la <= l && r <= ra)
    {
        if (f[k].tagtag)
        {
            //f[k].st += f[k].tag;
        }
        //f[k].tagtag = f[k].tag = 0;
        ll sst = st + (l - la) * d;
        f[k].sum += (sst + (f[k].s - 1) * d + sst) * f[k].s / 2;
        f[k].st += sst;
        f[k].d += d;
        f[k].sttag = 1;
        return;
    }
    down(k);
    int m = (l + r) >> 1;
    if (la <= m) update1(la,ra,lson,st,d);
    if (m < ra) update1(la,ra,rson,st,d);
    up(k);
}
void update2(int la,int ra,int l,int r,int k,int d)
{
    if (la <= l && r <= ra)
    {
        f[k].tagtag = 1;
        f[k].tag = d;
        f[k].st = f[k].d = 0;
        f[k].sum = f[k].s * f[k].tag;
        f[k].sttag = 0;
        return;
    }
    down(k);
    int m = (l + r) >> 1;
    if (la <= m) update2(la,ra,lson,d);
    if (m < ra) update2(la,ra,rson,d);
    up(k);
}
ll query(int la,int ra,int l,int r,int k)
{
    if (la <= l && r <= ra)
    {
//        put(k);
        return f[k].sum;
    }
    down(k);
    ll res = 0;
    int m = (l + r) >> 1;
    if (la <= m) res += query(la,ra,lson);
    if (m < ra) res += query(la,ra,rson);

    up(k);
    return res;
}
int main()
{
//    freopen("in.txt","r",stdin);
    n = 250000;
    int t;
    while (~scanf("%d",&t))
    {
        mk(1,n,1);
        //printf("%I64d\n",query(1,n,1,n,1));
        for (int i = 1;i <= t;i++)
        {
            int a,b,c;
            char ch[10];
            scanf("%s",ch);
            if (ch[0] == 'A')
            {
                scanf("%d %d",&a,&b);
                update1(a,b,1,n,1,1,1);
            }
            if (ch[0] == 'B')
            {
                scanf("%d %d",&a,&b);
                update1(a,b,1,n,1,b-a+1,-1);
            }
            if (ch[0] == 'C')
            {
                scanf("%d %d %d",&a,&b,&c);
                update2(a,b,1,n,1,c);
            }
            if (ch[0] == 'S')
            {
                scanf("%d %d",&a,&b);
                printf("%lld\n",query(a,b,1,n,1));
            }
            //printf("%I64d\n",f[212645].sum);
        }
       //printf("%I64d\n",f[2].sum);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值