HDU-4578:Transformation(有条件的延迟标记)

题目链接:点击打开链接


题目大意:

对一段区间进行操作,一共有四种操作

(1)   将一段区间内的数都加上c

(2)   将一段区间内的数都乘上c

(3)   将一段区间的数都变成c

(4)   统计一段区间内所有数的 p 次方的和。但是 p只有 1到3

解题思路:

看到是ICPC的题目,就决定自己好好做。上来一看8秒,我懂了,直接延迟更新,查询的时候再搜到子节点,然后加个次方,然后t了,

然后想了一下,恩,不对。不能这样,太耗时了,后来注意到p的范围只有1到3,惊了,遂决定维护三个值,分别表示p分别为 1 2 3时候的和,但是这样延迟更新就很麻烦,我 想都这样了,那就只延迟更新 3 操作吧。恩,然后t了。

我去,还能怎么简化,想了想,如果这段区间先执行过操作3的话并打了标记,那么操作1的变化值可以直接累加上去,恩,我找到了解题的关键,写上去,t了。

我日,仔细想了半天,真tm智障啊,(2)操作和(1)操作不是一样的嘛,适用于(1)的更新方法同样适用于(2)啊,同样可以延迟啊,加上以后,然后wa了。

真没辙了,开始仔细看代码,感觉自己代码绝对没有错误。检查许久,我终于在不起眼的地方发现了错误。超级容易漏掉的地方!!!

就是每次延迟更新的累加值一定要取余,一定要取余!!! 遂AC

然后删掉了一些自己认为不重要的地方,想让代码好看点,然后wa了。我~~那就这样吧,

总体思路就是如果一段区间之前被操作3打过标记的话,那么再在这段区间进行类似(1)(2)的操作就是可以直接累加到变化值里,就跟正常的延迟更新一样,如果没有的话,就直接更新到子节点。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <set>
#include <functional>
#define rank ra
#define lson rt<<1
#define rson rt<<1|1
#define pb push_back
using namespace std;
typedef long long ll;
const int INF = 1e9 + 5;
const int mod=10007;
int n,m;
int ans;
struct node
{
    int l,r,mid;
    int lazy;       //是否进行过操作3同时也是延迟更新的标记
    int c;          //延迟更新的变化值
    int sum1;       //次方分别1到3的和
    int sum2;
    int sum3;
}t[500000];
void pushup(int rt)
{
    t[rt].sum1=(t[lson].sum1+t[rson].sum1)%mod;
    t[rt].sum2=(t[lson].sum2+t[rson].sum2)%mod;
    t[rt].sum3=(t[lson].sum3+t[rson].sum3)%mod;
}
void pushdown(int rt)
{
    if(t[rt].lazy)      //延迟更新,因为操作3的特性,所以直接更新
    {
        t[lson].sum1=t[rt].c*(t[lson].r-t[lson].l+1)%mod;
        t[lson].sum2=t[rt].c*t[lson].sum1%mod;
        t[lson].sum3=t[rt].c*t[lson].sum2%mod;
        t[rson].sum1=t[rt].c*(t[rson].r-t[rson].l+1)%mod;
        t[rson].sum2=t[rt].c*t[rson].sum1%mod;
        t[rson].sum3=t[rt].c*t[rson].sum2%mod;
        t[rson].c=t[lson].c=t[rt].c;
        t[rson].lazy=t[lson].lazy=t[rt].lazy;
        t[rt].c=t[rt].lazy=0;
    }
}
void build(int l,int r,int rt)
{
    int mid=(l+r)>>1;
    t[rt].l=l;t[rt].r=r;
    t[rt].mid=mid;
    t[rt].sum1=t[rt].sum2=t[rt].sum3=t[rt].lazy=t[rt].c=0;
    if(l==r)
        return ;
    build(l,mid,lson);
    build(mid+1,r,rson);
    pushup(rt);
}
void update(int l,int r,int flag,int c,int rt)
{

    if(l<=t[rt].l&&t[rt].r<=r&&(t[rt].lazy==1||flag==3))    //是3操作或者是1 2操作但是执行过操作3
    {
        if(flag==3)
        {
            t[rt].lazy=1;
            t[rt].c=c;
        }
        if(flag==1)         //变化值累加
            t[rt].c += c;
        if(flag==2)
            t[rt].c=t[rt].c*c;
        t[rt].c=t[rt].c%mod;        //注意一定要取余
        t[rt].sum1=t[rt].c*(t[rt].r-t[rt].l+1)%mod;
        t[rt].sum2=t[rt].c*t[rt].sum1%mod;
        t[rt].sum3=t[rt].c*t[rt].sum2%mod;
        return ;
    }
    if(flag!=3&&l<=t[rt].l&&t[rt].r<=r&&t[rt].l==t[rt].r)      //没有的话就更新到子节点
    {
        if(flag==1)
            t[rt].sum1=(t[rt].sum1+c)%mod;
        if(flag==2)
            t[rt].sum1=(t[rt].sum1*c)%mod;
        t[rt].sum2=t[rt].sum1*t[rt].sum1%mod;
        t[rt].sum3=t[rt].sum2*t[rt].sum1%mod;
        return ;
    }
    pushdown(rt);
    if(l<=t[rt].mid)
        update(l,r,flag,c,lson);
    if(r>t[rt].mid)
        update(l,r,flag,c,rson);
    pushup(rt);
}
void query(int l,int r,int c,int rt)        //正常查询
{
    if(l<=t[rt].l&&t[rt].r<=r)
    {
        if(c==1)
            ans += t[rt].sum1;
        if(c==2)
            ans += t[rt].sum2;
        if(c==3)
            ans += t[rt].sum3;
        ans=ans%mod;
        return ;
    }
    pushdown(rt);
    if(l<=t[rt].mid)
        query(l,r,c,lson);
    if(r>t[rt].mid)
        query(l,r,c,rson);
    pushup(rt);
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)
            break;
        build(1,n,1);
        int q,l,r,c;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d%d",&q,&l,&r,&c);
            if(q>=1&&q<=3)
                update(l,r,q,c,1);
            if(q==4)
            {
                ans=0;
                query(l,r,c,1);
                printf("%d\n",ans%mod);
            }
        }
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值