poj 3468 线段树 区间内的线段和(成段更新)
来源:互联网 发布:网络棋牌赌博平台出租 编辑:程序博客网 时间:2024/05/16 04:49
题意:基本从题目可以知道了吧~
思路:直接线段树搞TLE,后来看了这个报告
http://hi.baidu.com/lewutian/blog/item/95421b828f63f19df603a6a2.html
知道了,在插入线段的时候不需要一直插到叶子节点,而是用一个“score”来标记某一段区间内的增值。 比如要在 【3 6】 区间插个 3 在找到【 4 5 】 区间的时候就可以把
【4 5】区间节点的“score”的更新成3。哎~看了报告还WA了半天,原来还真有long long 卡你的数据啊。。。悲催。写了这么长的代码,发现对"hh"大牛的线段树模版的仰慕犹如“滔滔江水,连绵不绝”啊。。。那犀利的小位运算和预处理~ 膜拜Orz...一定要拜读~掌握!!!
#include<iostream>using namespace std;struct node{ int lv,rv; long long score;//这个优化很见效嘛 写成int 看答案也没注意 WA吐血了。。。 long long sum; int mid() { return (lv+rv)/2; }}e[10000000];long long num[100010];void make_ST(int left,int right,int k){ //printf("%d\n",k); e[k].lv=left; e[k].rv=right; e[k].score=0; if(left==right) { e[k].sum=num[left]; return; } int midd=e[k].mid(); make_ST(left,midd,2*k); make_ST(midd+1,right,2*k+1); e[k].sum=(e[2*k].sum+e[2*k+1].sum); return;}void add_ST(int left,int right,int k,long long len){ if(e[k].lv>=left&&e[k].rv<=right) { e[k].score+=len;//成段更新 例如更新3--6 找到了[4,5] 就不用往下找了,记录下4-5每一段应该增加的长度 return; } else if(e[k].lv<=left&&right<=e[k].rv) e[k].sum+=((right-left+1)*len); else if(e[k].lv>=left&&right<=e[k].rv) e[k].sum+=((right-e[k].lv+1)*len); else if(e[k].lv<=left&&right>=e[k].rv) e[k].sum+=((e[k].rv-left+1)*len); int midd=e[k].mid(); if(midd>=left) add_ST(left,right,2*k,len); if(midd<right) add_ST(left,right,2*k+1,len); return;}long long sum;void query(int left,int right,int k){ if(e[k].lv>=left&&e[k].rv<=right) { sum+=(e[k].sum+e[k].score*(e[k].rv-e[k].lv+1)); return; } else //把这个节点的score信息更新到子节点,因为子节点的score不改变的话,最后求和的时候会出现错误 { e[2*k].score+=e[k].score; e[2*k+1].score+=e[k].score; e[k].sum+=(e[k].score*(e[k].rv-e[k].lv+1));//把增加的数值记录到sum里,score的使命也就完成了,下一步就销毁score e[k].score=0;//用完就销毁。。。如此残忍。。。 } int midd=e[k].mid(); if(midd>=left) query(left,right,2*k); if(midd<right) query(left,right,2*k+1); return;}int main(){ int N,Q,left,right; long long len; char s[2]; while(scanf("%d%d",&N,&Q)!=EOF) { for(int i=1;i<=N;i++) { scanf("%lld",&num[i]); //printf("%d\n",num[i]); } make_ST(1,N,1); while(Q--) { scanf("%s",s); if(s[0]=='Q') { scanf("%d%d",&left,&right); sum=0; query(left,right,1); printf("%lld\n",sum); } else { scanf("%d%d%lld",&left,&right,&len); add_ST(left,right,1,len); } } } return 0;}
HH版本的
#include<iostream>using namespace std;#define LL long long#define lson l , m , rt << 1#define rson m + 1 , r , rt << 1 | 1const int maxn = 100005;LL sum[maxn<<2];LL add[maxn<<2];void PushUP(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; }void PushDown(int rt,int m) { if (add[rt]) { //printf("rat=%d\n",rt); add[rt<<1] += add[rt]; add[rt<<1|1] += add[rt]; sum[rt<<1] += add[rt] * (m - (m >> 1)); sum[rt<<1|1] += add[rt] * (m >> 1); add[rt] = 0; } }void build(int l,int r,int rt) { add[rt] = 0; if (l == r) { scanf("%lld",&sum[rt]); return ; } int m = (l + r) >> 1; build(lson); build(rson); PushUP(rt);}void update(int L,int R,LL len,int l,int r,int rt) { if (L <= l && R >= r) { //printf("rt=%d\n",rt); add[rt] += len; sum[rt] += (len * (r - l + 1)); return ; } int m = (l + r) >> 1; PushDown(rt , r - l + 1); if (m >= L) update(L , R , len , lson); if (m < R) update(L , R , len , rson); PushUP(rt); }LL query(int L,int R,int l,int r,int rt) { if (L <=l && R >= r) { return sum[rt]; } int m = (l + r) >> 1; PushDown(rt , r - l + 1); LL ret = 0; if (m >= L) ret += query(L , R , lson); if (m < R) ret += query(L , R , rson); return ret; }int main() { int N,Q; while (scanf("%d%d",&N,&Q)!=EOF) { build(1 , N , 1); char s[4]; int a , b; LL len; while (Q --) { scanf("%s",s); if (s[0] == 'Q') { scanf("%d%d",&a,&b); printf("%lld\n",query(a , b , 1 , N , 1)); } else { scanf("%d%d%lld",&a,&b,&len); update(a , b , len , 1 , N , 1); } } } }
- poj 3468 线段树 区间内的线段和(成段更新)
- POJ 3468 【线段树区间更新-成段更新】
- poj 3468 A Simple Problem with Integers(线段树|成段更新,区间查询)
- POJ 3468-A Simple Problem with Integers(线段树:成段更新,区间求和)
- POJ 3667 Hotel 线段树 区间合并(成段更新)
- POJ 3667(线段树,区间合并,成段更新)
- Poj 3468 线段树的区间更新
- poj 3468 线段树(成段增减 区间求和)
- poj 3468 线段树 成段更新
- poj 3468 线段树--成段更新
- poj 3468线段树 成段更新
- POJ 3468 线段树(区间更新)
- 线段树 区间更新(成段更新) HDU1698
- 线段树 成段更新区间操作
- 线段树,成段更新,区间求和
- POJ 3468 A Simple Problem with Integers(段更新的区间求和&Lazy思想&线段树)
- POJ 3468 A Simple Problem with Integers (线段树,成段更新,区间求和)
- Poj 1823 Hotel (线段树 区间合并 成段更新)
- HTTP Request GET, HEAD, POST, PUT, DELETE, OPTIONS, TRACE Methods
- andorid 的shape用法
- Effective C++ Item 1:View C++ as a federation of languages
- aMule的命令行编译
- [入门扫盲]开发人员不能不知道的几个开发工具
- poj 3468 线段树 区间内的线段和(成段更新)
- .NET创建XML文件
- c 语言写的fastcgi 程序
- C#委托解析(收藏)
- Red Hat Enterprise 5中make xconfig命令不能使用的说明
- javascript 分模块架构
- PKU-静态成员作业-程设hw03
- 腾讯的产品管理之道
- JavaScript提升性能之事件委托