HDU4578 Transformation 线段树

这个题让我重新学习了加 乘 在区间的操作

题解:http://blog.csdn.net/guognib/article/details/25324025?utm_source=tuicool&utm_medium=referral

代码:也是参考上面的写的

注:确实有优先级,加只影响自己,乘会影响加,重新设定值会清零所有的标记

所以向下传的时候,乘和加的操作都晚于最后一次设定值,然后乘的操作要先于加

所以要先传递set 然后是mul 然后是add

#include <stdio.h>
#include <string.h>
#include <string>
#include <math.h>
#include <stack>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=1e5+5;
const int mod=10007;
int q[3][N<<2],setval[N<<2],add[N<<2],mul[N<<2];
void pushup(int rt){
    for(int i=0;i<3;++i)
      q[i][rt]=(q[i][rt<<1]+q[i][rt<<1|1])%mod;
}
void downset(int rt,int c,int len){
    int a[4];a[1]=c;
    for(int i=2;i<=3;++i)
      a[i]=a[i-1]*a[1]%mod;
    for(int i=0;i<3;++i)
     q[i][rt]=a[i+1]*len%mod;
    setval[rt]=c;
    add[rt]=0;
    mul[rt]=1;
}
void downadd(int rt,int c,int len){
    int a[4];a[1]=c;
    for(int i=2;i<=3;++i)
       a[i]=a[i-1]*a[1]%mod;
    q[2][rt]=q[2][rt]+a[3]*len%mod+3*a[2]%mod*q[0][rt]%mod+3*a[1]%mod*q[1][rt]%mod;
    q[1][rt]=q[1][rt]+a[2]*len%mod+2*a[1]%mod*q[0][rt]%mod;
    q[0][rt]=q[0][rt]+a[1]*len%mod;
    for(int i=0;i<3;++i)q[i][rt]%=mod;
    add[rt]=(add[rt]+c)%mod;
}
void downmul(int rt,int c,int len){
   int a[4];a[1]=c;
   for(int i=2;i<=3;++i)
    a[i]=a[i-1]*a[1]%mod;
   for(int i=0;i<3;++i)
    q[i][rt]=(q[i][rt]*a[i+1])%mod;
   mul[rt]=(mul[rt]*c)%mod;
   add[rt]=(add[rt]*c)%mod;
}
void down(int rt,int l,int r){
    int m=(l+r)>>1;
    if(setval[rt]!=-1){
        downset(rt<<1,setval[rt],m-l+1);
        downset(rt<<1|1,setval[rt],r-m);
        setval[rt]=-1;
    }
    if(mul[rt]!=1){
        downmul(rt<<1,mul[rt],m-l+1);
        downmul(rt<<1|1,mul[rt],r-m);
        mul[rt]=1;
    }
    if(add[rt]!=0){
        downadd(rt<<1,add[rt],m-l+1);
        downadd(rt<<1|1,add[rt],r-m);
        add[rt]=0;
    }
}
int op,c;
void modify(int rt,int l,int r,int x,int y){
    if(x<=l&&r<=y){
        if(op==1)downadd(rt,c,r-l+1);
        else if(op==2)downmul(rt,c,r-l+1);
        else downset(rt,c,r-l+1);
        return;
    }
    int m=(l+r)>>1;
    down(rt,l,r);
    if(x<=m)modify(rt<<1,l,m,x,y);
    if(y>m)modify(rt<<1|1,m+1,r,x,y);
    pushup(rt);
}
int ask(int rt,int l,int r,int x,int y){
    if(x<=l&&r<=y)return q[c-1][rt];
    int ans=0,m=(l+r)>>1;
    down(rt,l,r);
    if(x<=m)ans=(ans+ask(rt<<1,l,m,x,y))%mod;
    if(y>m)ans=(ans+ask(rt<<1|1,m+1,r,x,y))%mod;
    return ans;
}
int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        if(!n&&!m)break;
        for(int i=0;i<=4*n;++i){
            q[0][i]=q[1][i]=q[2][i]=add[i]=0;
            mul[i]=1;
            setval[i]=-1;
        }
        while(m--){
            int x,y;
            scanf("%d%d%d%d",&op,&x,&y,&c);
            if(op<=3)modify(1,1,n,x,y);
            else printf("%d\n",ask(1,1,n,x,y));
        }
    }
    return 0;
}

时间: 2024-08-17 06:29:34

HDU4578 Transformation 线段树的相关文章

HDU 4578 Transformation --线段树,好题

题意: 给一个序列,初始全为0,然后有4种操作: 1. 给区间[L,R]所有值+c 2.给区间[L,R]所有值乘c 3.设置区间[L,R]所有值为c 4.查询[L,R]的p次方和(1<=p<=3) 解法: 线段树,维护三个标记,addmark,mulmark,setmark分别表示3种更新,然后p[1],p[2],p[3]分别表示该节点的1,2,3次方和.标记传递顺序setmark一定是第一个,因为setmark可以使mulmark,addmark都失效还原,mulmark和addmark的顺

hdu 4578 Transformation(线段树)

Transformation Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 65535/65536 K (Java/Others)Total Submission(s): 3084    Accepted Submission(s): 749 Problem Description Yuanfang is puzzled with the question below: There are n integers, a1, a2,

Transformation(线段树多个lz标记)

这里以3次方来举例讲一下这题的做法,其它维类似. 如果要求某一个值的3次方那么sum = t^3,设t = x+y.那也就是sum = (x+y)^3. 假如我让每个数都加z t = x+y+z,我可以让新的y = y+z,这里发现新来的总会加在y上,那么可以给他一个延迟,slz, 那么新的值t = t + slz,再看如果让每个数都乘k,t = (x+y)*k = xk+yk.可以看出刚才的slz = slz*k; 另外发现系数会跟着变换,可以给他一个延迟,mlz. 那么一个数t = (mlz

HDU 4578 - Transformation - [加强版线段树]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578 Problem Description Yuanfang is puzzled with the question below: There are n integers, a1, a2, -, an. The initial values of them are 0. There are four kinds of operations.Operation 1: Add c to each

HDU4578 线段树(区间更新 + 多种操作)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578  , 线段树的区间更新 + 多种操作,好题. 虽然是比较裸的线段树,但是比较麻烦,并且有很多细节需要考虑,最后我7.3s很惊险地过了,求大神告知优化方法. 这道题坑在有三种询问:set , add , mul.所以lazy标记要有三个,如果三个标记同时出现的处理方法——当更新set操作时,就把add标记和mul标记全部取消:当更新mul操作时,如果当前节点add标记存在,就把add标记改为:a

[HDOJ4578]Transformation(线段树,多延迟标记)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578 四种操作:查询.加法.乘法.改数.应该是需要维护三个lazy标记,然后就是套路了.查询是区间内所有的数的p次幂然后再求和,这个p只有三个值(1,2,3),直接维护三棵线段树,分别是1 2 3次幂. 注意延迟标记的时候,如果有改数,那之前的加法和乘法就可以不用做了.在更新乘法的时候,如果有加法存在,那加法的标记应该更新,乘一下乘法的数,因为(a+b)*c = a*c+b*c,父亲是a+b,儿子是

线段树题目总结

一.单点更新 1.hdu1166 敌兵布阵:有N个兵营,每个兵营都给出了人数ai(下标从1开始),有四种命令,(1)"Addij",表示第i个营地增加j人.(2)"Sub i j",表示第i个营地减少j人.(3)"Query ij",查询第i个营地到第j个营地的总人数.(4)"End",表示命令结束.解题报告Here. 2.hdu1754 I Hate It:给你N个数,M个操作,操作分两类.(1)"QAB"

线段树总结 (转载 里面有扫描线类 还有NotOnlySuccess线段树大神的地址)

转载自:http://blog.csdn.net/shiqi_614/article/details/8228102 之前做了些线段树相关的题目,开学一段时间后,想着把它整理下,完成了大牛NotOnlySuccess的博文“完全版线段树”里的大部分题目,其博文地址Here,然后也加入了自己做过的一些题目.整理时,更新了之前的代码风格,不过旧的代码仍然保留着. 同样分成四类,不好归到前四类的都分到了其他.树状数组能做,线段树都能做(如果是内存限制例外),所以也有些树状数组的题目,会标示出来,并且放

ZOJ 2671 Cryptography 矩阵乘法+线段树

B - Cryptography Time Limit:5000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit Status Practice ZOJ 2671 Description Young cryptoanalyst Georgie is planning to break the new cipher invented by his friend Andie. To do this, he must