[codevs4919] 线段树练习4

  • 为什么要写这个看上去很水的题的题解呢..因为它坑点太多了,我足足调了1个上午+1个晚上+一整天。
  • 还是分块大法吼啊,分块大法保平安。
  • 题意(原题):
  • 数列区间加法,区间求%7=0的元素个数。
  • 思路:
  • 这题特别坑…主要的坑点在于它不像普通区间加法区间求和一样,区间加法只需要给自己加上特征值然后改一下lazy,它的更新是需要用到他的子节点的信息的,所以treeAdd的时候也要分发lazy,还有一大堆坑点都忘光了。。手造了n个错误数据,一个个调试修掉,然后还是wa,然后又对拍了n个错误数据全部改掉才ac,真的心累。
  • 代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN (110000)
using namespace std;
struct node
{
    int l,r,mid,ls,rs,lazy,val[7];
    node()
    {
        l=r=mid=ls=rs=0;
        memset(val,0,sizeof(val));
    }
}a[MAXN*2];
char ss[11];
int n,m,len=0,readVal[MAXN];
void treeAddVal(int x,int val)
{
    val%=7;
    node x2=a[x];
    for(int i=0;i<=6;i++)
        a[x].val[(i+val)%7]=x2.val[i];
    return ;
}
void treeAddLazy(int x,int val)
{
    a[x].lazy+=val;
    treeAddVal(x,val);
}
void treeUpdate(int x)
{
    memset(a[x].val,0,sizeof(a[x].val));
    for(int i=0;i<=6;i++)
        a[x].val[i]=a[a[x].ls].val[i]+a[a[x].rs].val[i];
}
void treeBuild(int l,int r)
{
    int now=++len;
    a[now].l=l;a[now].r=r;a[now].mid=(l+r)/2;
    a[now].lazy=0;
    if(l==r)
        a[now].val[readVal[l]%7]++;
    else
    {
        a[now].ls=len+1;
        treeBuild(l,a[now].mid);

        a[now].rs=len+1;
        treeBuild(a[now].mid+1,r);

        treeUpdate(now);
    }
    return;
}
int treeGetAns(int now,int l,int r)
{
    if(a[now].l==a[now].r||(a[now].l==l&&a[now].r==r))return a[now].val[0];

    if(a[now].lazy)
    {
        treeAddLazy(a[now].ls,a[now].lazy);
        treeAddLazy(a[now].rs,a[now].lazy);
        a[now].lazy=0;
    }
    treeUpdate(now);

    int ans=0;
    if(l<=a[now].mid)ans+=treeGetAns(a[now].ls,l,min(r,a[now].mid));
    if(r>=a[now].mid+1)ans+=treeGetAns(a[now].rs,max(l,a[now].mid+1),r);
    treeUpdate(now);
    return ans;
}
void treeAdd(int now,int l,int r,int val)
{
    if(a[now].l==a[now].r)
    {
        treeAddVal(now,val);
        return;
    }
    if(a[now].l==l&&a[now].r==r)
    {
        treeAddLazy(now,val);
        return;
    }
    if(a[now].lazy)
    {
        treeAddLazy(a[now].ls,a[now].lazy);
        treeAddLazy(a[now].rs,a[now].lazy);
        a[now].lazy=0;
    }
    if(l<=a[now].mid)treeAdd(a[now].ls,l,min(r,a[now].mid),val);
    if(r>=a[now].mid+1)treeAdd(a[now].rs,max(l,a[now].mid+1),r,val);

    treeUpdate(now);
    return;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&readVal[i]);
    treeBuild(1,n);
    scanf("%d",&m);
    while(m--)
    {
        scanf("%s",ss+1);
        int x,y,z;
        if(ss[1]=='c')
        {
            scanf("%d%d",&x,&y);
            printf("%d\n",treeGetAns(1,x,y));
        }   
        else
        {
            scanf("%d%d%d",&x,&y,&z);
            treeAdd(1,x,y,z);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值