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

来源:互联网 发布:自导自演 周杰伦 知乎 编辑:程序博客网 时间:2024/06/05 09:29

题目链接:点击打开链接


题目大意:

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

(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_backusing 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);            }        }    }}




原创粉丝点击