hdu-4587-线段树的区间操作- lazy标记
来源:互联网 发布:淘宝儿童卡通墙贴 编辑:程序博客网 时间:2024/05/16 05:07
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=4578
题目大意:给你一个数组,初始值为零
1 x y c 代表 把区间 [x,y] 上的值全部加c
2 x y c 代表 把区间 [x,y] 上的值全部乘以c
3 x y c 代表 把区间 [x,y]上的值全部赋值为c
4 x y p 代表 求区间 [x,y] 上值的p次方和1<=p<=3
线段树属于初学阶段 一开始就不会 经过一个晚上的调试和网上找资料
附上3个链接
关于线段树lazy标记的研究(1)
关于线段树lazy标记的研究(2)
关于线段树lazy标记的研究(3)
是pasca 语言写的自己翻译了一下, 里面说的很清楚,有点小小的错误就是研究(3)里面update里面特殊判断改为if(tree[i*2].cov!=-1) 和 if(tree[i*2+1].cov!=-1)
代码如下
#include <iostream>#include <cstdio>#include <cstring>#define MOD 10007#define MAX 100010using namespace std;typedef struct{ int l; int r; int sum[4]; int cnt; //加法 int val; //乘法 int cov; //赋值} Tree;Tree tree[MAX*10];int i,j,k,m,n,x,y,ch;void update(int i) //更新{ int s1[4],s2[4]; s1[0]=1,s2[0]=1; if(tree[i].cov!=-1) //赋值优先 { for(int j=1; j<=3; j++) s1[j]=(s1[j-1]*tree[i].cov)%MOD; tree[i].sum[1]=(s1[1]*(tree[i].r-tree[i].l+1))%MOD; tree[i].sum[2]=(s1[2]*(tree[i].r-tree[i].l+1))%MOD; tree[i].sum[3]=(s1[3]*(tree[i].r-tree[i].l+1))%MOD; tree[i*2].cov=tree[i].cov; tree[i*2].cnt=0; tree[i*2].val=1; tree[i*2+1].cov=tree[i].cov; tree[i*2+1].cnt=0; tree[i*2+1].val=1; tree[i].cov=-1; tree[i].cnt=0; tree[i].val=1; } else if(tree[i].cnt!=0||tree[i].val!=1) //加法和乘法可以合并 { for(int j=1; j<=3; j++) { s1[j]=(s1[j-1]*tree[i].cnt)%MOD; s2[j]=(s2[j-1]*tree[i].val)%MOD; } tree[i].sum[3]= ((tree[i].sum[3]*s2[3])%MOD +((tree[i].r-tree[i].l+1)*s1[3])%MOD + (3*((s2[2]*s1[1])%MOD)*tree[i].sum[2])%MOD + ((3*(s2[1]*s1[2])%MOD)*tree[i].sum[1])%MOD )%MOD; // 求3次方和 tree[i].sum[2]= ((tree[i].sum[2]*s2[2])%MOD +((tree[i].r-tree[i].l+1)*s1[2])%MOD + ((2*(tree[i].sum[1]*s1[1])%MOD)*s2[1])%MOD )%MOD; //求平方和 tree[i].sum[1]= ((tree[i].sum[1]*s2[1])%MOD +((tree[i].r-tree[i].l+1)*s1[1])%MOD)%MOD; //求和 if( tree[i*2].cov!=-1) //特殊判断 tree[i*2].cov=(tree[i*2].cov*s2[1]+s1[1])%MOD; else { tree[i*2].cnt =(s2[1]*tree[i*2].cnt + tree[i].cnt)%MOD; tree[i*2].val = (tree[i*2].val*tree[i].val)%MOD; } // 往左子节点更新 if(tree[i*2+1].cov!=-1) //t特殊判断 tree[i*2+1].cov=(tree[i*2+1].cov*s2[1]+s1[1])%MOD; else { tree[i*2+1].cnt=(s2[1]*tree[i*2+1].cnt + tree[i].cnt)%MOD; //往右子节点更新加法 tree[i*2+1].val=(tree[i*2+1].val*tree[i].val)%MOD; //往右子节点更新乘法 } tree[i].cnt=0; // tree[i].val=1; }}int build(int i,int l,int r){ int mid; tree[i].l=l; tree[i].r=r; tree[i].sum[1]=0; tree[i].sum[2]=0; tree[i].sum[3]=0; tree[i].cnt =0; tree[i].val =1; tree[i].cov=-1; if(l==r) { return 0; } mid=(l+r)/2; build(i*2,l,mid); build(i*2+1,mid+1,r); //tree[i].sum[1]=(tree[i*2].sum[1]+tree[i*2+1].sum[1])%MOD;}int cover(int i,int x,int y,int now) //赋值{ int mid; update(i); //更新 if((x<=tree[i].l)&&(y>=tree[i].r)) { tree[i].cov=now; tree[i].cnt=0; tree[i].val=1; return 0; } mid=(tree[i].l+tree[i].r)/2; if(x<=mid) cover(i*2,x,y,now); if(y > mid) cover(i*2+1,x,y,now); update(i*2); update(i*2+1); tree[i].sum[1]=(tree[i*2].sum[1]+tree[i*2+1].sum[1])%MOD; tree[i].sum[2]=(tree[i*2].sum[2]+tree[i*2+1].sum[2])%MOD; tree[i].sum[3]=(tree[i*2].sum[3]+tree[i*2+1].sum[3])%MOD;}int ins(int i,int x,int y,int v,int c) //加法和乘法可以合并{ int mid; update(i); if ((x<=tree[i].l)&&(y>=tree[i].r)) { tree[i].val=(tree[i].val*v)%MOD; tree[i].cnt=(tree[i].cnt*v+c)%MOD; return 0; } mid=(tree[i].l+tree[i].r)/2; if (x<=mid) ins(i*2, x,y,v,c); if (y>mid) ins(i*2+1,x,y,v,c); update(i*2); update(i*2+1); tree[i].sum[1] = (tree[i*2].sum[1]+tree[i*2+1].sum[1])%MOD; tree[i].sum[2] = (tree[i*2].sum[2]+tree[i*2+1].sum[2])%MOD; tree[i].sum[3] = (tree[i*2].sum[3]+tree[i*2+1].sum[3])%MOD;}int cal(int i,int x,int y,int k) //计算{ int mid; int ans[4]; update(i); if ((x<=tree[i].l)&&(y>=tree[i].r)) return (tree[i].sum[k]); ans[k]=0; mid=(tree[i].l+tree[i].r)/2; if (x<=mid) ans[k]=(ans[k]+cal(i*2,x,y,k))%MOD; if (y>mid) ans[k]=(ans[k]+cal(i*2+1,x,y,k))%MOD; update(i*2); update(i*2+1); tree[i].sum[1]=(tree[i*2].sum[1]+tree[i*2+1].sum[1])%MOD; tree[i].sum[2]=(tree[i*2].sum[2]+tree[i*2+1].sum[2])%MOD; tree[i].sum[3]=(tree[i*2].sum[3]+tree[i*2+1].sum[3])%MOD; return ans[k];}int main(){ while(~scanf("%d%d",&n,&m)) { if(n==0||m==0) break; build(1,1,n); for (i=1; i<=m; i++) { scanf("%d",&ch); switch(ch) { case 1: { scanf("%d%d%d",&x,&y,&k); //加法 if(k!=0) ins(1,x,y,1,k); break; } case 2: { scanf("%d%d%d",&x,&y,&k); //乘法 if(k!=1) ins(1,x,y,k,0); break; } case 3: { scanf("%d%d%d",&x,&y,&k); //赋值 cover(1,x,y,k); break; } case 4: { scanf("%d%d%d",&x,&y,&k);//查询 printf("%d\n",cal(1,x,y,k)); break; } } } }}
- hdu-4587-线段树的区间操作- lazy标记
- hdu 1698 线段树区间更新入门(lazy标记)
- SKYLINE uva+线段树+区间的修改+lazy标记
- 线段树区间修改 lazy标记 大法
- 线段树模板(区间和+区间最大值 + LAZY标记)
- hdu 4578 线段树lazy标记
- hdu 3397 Sequence operation (线段树+区间合并+双Lazy标记)
- HDU 1698-Just a Hook(线段树_区间更新+lazy标记)
- hdu 1556 color the ball 线段树区间更新 加lazy标记
- 线段树学习笔记(单点更新+区间查询最大值+lazy标记+pushdown操作+区间更新+求区间和)
- coj 1123 带区间操作的线段树(lazy)
- 线段树lazy标记
- 线段树区间更新模板(lazy延迟标记)(1698)
- 专题 线段树 E(区间更新,使用lazy标记)
- 线段树求区间最大值+区间更新+区间求和+lazy标记
- HDU 3911 Black And White(线段树区间合并+lazy操作)
- hdu 3954(线段树的特殊lazy操作)
- 线段树区间修改之双标记 【lazy两重标记并且分类讨论】
- 土耳其旅游记录
- 黑马程序员_Asp.Net防盗链
- C++类成员函数指针和一般函数指针的编译模式的差别
- SPUser with person and group field
- 走进谷歌 -- 去了就不想离开的 Google 总部
- hdu-4587-线段树的区间操作- lazy标记
- 螺丝的参数
- hdu 1421 搬寝室
- c++ 多线程调试小技巧
- Flex FileReference 在Firefox 浏览器情况下的异常情况
- timus 1081. Binary Lexicographic Sequence URAL 解题报告
- eclipse添加logcat显示
- 灵活配置自动化测试环境
- 用SecureCRT连接VMware中的Linux系统