线段树成段更新模板POJ3468 zkw以及lazy思想

别人跑几百毫秒 我跑 2500多

  1 #include<cstdio>
  2 #include<map>
  3 //#include<bits/stdc++.h>
  4 #include<vector>
  5 #include<stack>
  6 #include<iostream>
  7 #include<algorithm>
  8 #include<cstring>
  9 #include<cmath>
 10 #include<queue>
 11 #include<cstdlib>
 12 #include<climits>
 13 #define INF 0x3f3f3f3f
 14 using namespace std;
 15 typedef long long ll;
 16 typedef __int64 int64;
 17 const ll mood=1e9+7;
 18 const int64 Mod=998244353;
 19 const double eps=1e-9;
 20 const int MAXN=100010;
 21 const double PI=acos(-1.0);
 22 inline void rl(ll&num){
 23     num=0;ll f=1;char ch=getchar();
 24     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 25     while(ch>=‘0‘&&ch<=‘9‘)num=num*10+ch-‘0‘,ch=getchar();
 26     num*=f;
 27 }
 28 inline void ri(int &num){
 29     num=0;int f=1;char ch=getchar();
 30     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 31     while(ch>=‘0‘&&ch<=‘9‘)num=num*10+ch-‘0‘,ch=getchar();
 32     num*=f;
 33 }
 34 int getnum()//相邻的个位整数输入 如想分别保存1234 输入连续的1234 a[i]=getnum();就可以实现
 35 {
 36     char ch=getchar();
 37     while((ch<‘0‘ || ch>‘9‘) && ch!=‘-‘)
 38         ch=getchar();
 39     return (ch-‘0‘);
 40 }
 41 inline void out(int x){ if(x<0) {putchar(‘-‘);  x*=-1;}if(x>9) out(x/10);    putchar(x%10+‘0‘); }
 42 ll sum[MAXN<<2],add[MAXN<<2];
 43 int n;
 44 void init(int _n)
 45 {
 46     n=1;
 47     while(n<_n) n*=2;
 48     for(int i=0;i<2*n-1;i++)
 49     {
 50         sum[i]=add[i]=0;
 51     }
 52 }
 53 void pushdown(int rt,int m)
 54 {
 55     if(add[rt])
 56     {
 57         add[rt*2+2] += add[rt];
 58         add[rt<<1|1] += add[rt];
 59         sum[rt*2+2] += add[rt] * (m - (m>>1));
 60         sum[rt<<1|1] += add[rt] * (m>>1);
 61         add[rt] = 0;
 62     }
 63 }
 64 void pushup(int rt)
 65 {
 66     sum[rt]=sum[rt*2+2]+sum[rt<<1|1];
 67 }
 68 void update(int a,int b,int c,int k,int l,int r)
 69 {
 70     if(r<=a||b<=l) return ;
 71     if(a<=l&&r<=b)
 72     {
 73         add[k]+=c;
 74         sum[k]+=(ll)c*(r-l);
 75         return ;
 76     }
 77     if(l+1==r) return;
 78     pushdown(k,r-l);
 79     int m=(l+r)/2;
 80     if(b<=m)
 81     {
 82         update(a,b,c,k*2+1,l,m);
 83     }
 84     else{
 85         if(l>m)update(a,b,c,k*2+2,m,r);
 86         else{
 87             update(a,b,c,k*2+1,l,m);
 88             update(a,b,c,k*2+2,m,r);
 89         }
 90     }
 91     pushup(k);
 92 }
 93 ll query(int a,int b,int k,int l,int r)
 94 {
 95     if(r<=a||b<=l) return 0;
 96     if(a<=l&&r<=b)
 97     {
 98         return sum[k];
 99     }
100     pushdown(k,r-l);
101     int m=(l+r)/2;
102     ll res=0;
103     if(b<=m)
104     {
105         res+=query(a,b,k*2+1,l,m);
106     }
107     else{
108         if(l>m)res+=query(a,b,k*2+2,m,r);
109         else{
110             res+=query(a,b,k*2+1,l,m);
111             res+=query(a,b,k*2+2,m,r);
112         }
113     }
114     return res;
115 }
116 void ad(int k,int a)
117 {
118     k+=n-1;
119     sum[k]=a;
120     while(k>0)
121     {
122         k=(k-1)/2;
123         sum[k]=sum[k*2+1]+sum[k*2+2];
124     }
125 }
126 int main()
127 {
128     int _n,m;
129     while(scanf("%d%d",&_n,&m)==2)
130     {
131         init(_n);
132         for(int i=1;i<=_n;i++)
133         {
134             int tem;
135             ri(tem);ad(i,tem);
136         }
137         char ch[2];
138
139         int a,b,c;
140         while(m--)
141         {
142             scanf("%s",ch);
143             if(ch[0] == ‘Q‘)
144             {
145                 scanf("%d %d", &a,&b);
146                 printf("%lld\n",query(a,b+1,0,0,n));
147             }
148
149             else
150             {
151                 scanf("%d %d %d",&a,&b,&c);
152                 update(a,b+1,c,0,0,n);
153             }
154         }
155         memset(add,0,sizeof(add));
156         memset(sum,0,sizeof(sum));
157     }
158     return 0;
159 }

等看能不能优化再写

时间: 2024-11-10 08:18:14

线段树成段更新模板POJ3468 zkw以及lazy思想的相关文章

线段树成段更新 hdu 1698 Just a Hook

题意:给出n根金属棒,和操作数q,初始时每个金属棒价值都为1,每次操作可以把从x到y的金属棒更换材质,铜为1,银为2,金为3,最后统计所有的金属棒总价值是多少. 线段树成段更新,需要用到lazy标记,所谓lazy标记就是:更新一个区间的时候不更新到底,只更新到第一个满足更新范围的区间(即范围内的最大的区间),然后给节点加上lazy标记,以后需要更新到该节点的子节点的时候,就把lazy标记转移到子节点上,这样大大提升了效率. 代码:

poj 3468 A Simple Problem with Integers (线段树成段更新)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 77486   Accepted: 23862 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

【POJ】3468 A Simple Problem with Integers ——线段树 成段更新 懒惰标记

A Simple Problem with Integers Time Limit:5000MS   Memory Limit:131072K Case Time Limit:2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each

Codeforces Round #149 (Div. 2) E. XOR on Segment (线段树成段更新+二进制)

题目链接:http://codeforces.com/problemset/problem/242/E 给你n个数,m个操作,操作1是查询l到r之间的和,操作2是将l到r之间的每个数xor与x. 这题是线段树成段更新,但是不能直接更新,不然只能一个数一个数更新.这样只能把每个数存到一个数组中,长度大概是20吧,然后模拟二进制的位操作.仔细一点就行了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cmath>

POJ 2777 Count Color (线段树成段更新+二进制思维)

题目链接:http://poj.org/problem?id=2777 题意是有L个单位长的画板,T种颜色,O个操作.画板初始化为颜色1.操作C讲l到r单位之间的颜色变为c,操作P查询l到r单位之间的颜色有几种. 很明显的线段树成段更新,但是查询却不好弄.经过提醒,发现颜色的种类最多不超过30种,所以我们用二进制的思维解决这个问题,颜色1可以用二进制的1表示,同理,颜色2用二进制的10表示,3用100,....假设有一个区间有颜色2和颜色3,那么区间的值为二进制的110(十进制为6).那我们就把

POJ 2528 Mayor&#39;s posters (hash+线段树成段更新)

题意:有一面墙,被等分为1QW份,一份的宽度为一个单位宽度.现在往墙上贴N张海报,每张海报的宽度是任意的,但是必定是单位宽度的整数倍,且<=1QW.后贴的海报若与先贴的海报有交集,后贴的海报必定会全部或局部覆盖先贴的海报.现在给出每张海报所贴的位置(左端位置和右端位置),问张贴完N张海报后,还能看见多少张海报?(PS:看见一部分也算看到.) 思路:简单的成段更新,但是数据量是1千万,会MT,所以要区间压缩(离散化),保证覆盖的关系不变,离散化的时候有个易错的细节,poj数据水了,这个易错点引用h

POJ训练计划2777_Count Color(线段树/成段更新/区间染色)

解题报告 题意: 对线段染色,询问线段区间的颜色种数. 思路: 本来直接在线段树上染色,lz标记颜色.每次查询的话访问线段树,求出颜色种数.结果超时了,最坏的情况下,染色可以染到叶子节点. 换成存下区间的颜色种数,这样每次查询就不用找到叶子节点了,用按位或来处理颜色种数. #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace

Light OJ 1411 Rip Van Winkle`s Code 线段树成段更新

题目来源:Light OJ 1411 Rip Van Winkle`s Code 题意:3中操作 1种查询 求区间和 其中每次可以把一段区间从左到右加上1,2,3,...或者从右到左加上...3,2,1 或者把某个区间的数都置为v 思路:我是加了6个域 add是这段区间每个数都要加上add  add是这么来的 对与123456...这个等差数列 可能要分为2个区间 那么我就分成123和123 两个右边的等差数列每个数还应该加上3 所以右区间add加3 v是这个区间都要置为v 他的优先级最高 b是

poj 3468 A Simple Problem with Integers 【线段树-成段更新】

题目:poj 3468 A Simple Problem with Integers 题意:给出n个数,两种操作 1:l -- r 上的所有值加一个值val 2:求l---r 区间上的和 分析:线段树成段更新,成段求和 树中的每个点设两个变量sum 和 num ,分别保存区间 l--r 的和 和l---r 每个值要加的值 对于更新操作:对于要更新到的区间上面的区间,直接进行操作 加上 (r - l +1)* val .下面的区间标记num += val 对于求和操作,每次进行延迟更新,把num值