ZKW线段树之旅(1)
来源:互联网 发布:c excel重复数据删除 编辑:程序博客网 时间:2024/06/02 05:53
膜拜ZKW神犇。。。。Orz。。。
ZKW线段树的思想是直接找到一个大区间对应的小区间
由于是自底向上的,所以常数很小(《统计的力量》)
其实我觉得,真正难写 的是区间修改
比如现在造一颗线段树,支持区间求和,区间修改
ZKW线段树有两种做法:
一是维护神奇 的前缀和的前缀和
二是沿用递归版线段树的思路,在 区间上打标记,然后统计
我 太弱,第一种不会。。。于是我就用第二种吧
区间修改:简单,就在区间上打个标记,顺便更新一下遍历到的区间和,最后当l和r父亲相同时,循环结束,再把他们的父亲们的和更新。
区间求和:先是记一下左边,右边 的区间里有几个元素要加,每次就根据遍历到的区间的标记更新答案。最后当l和r父亲相同时,循环结束,再把他们的父亲们的标记拿来更新答案
好像有点大话连篇。。。上代码好了
const int maxn=262144;int sumv[maxn],addv[maxn],m;//sumv 维护区间的和,addv是标记;m不说了吧,地球人都知道void update(int l,int r,int a){ l+=m-1,r+=m+1; int ln=0,rn=0;//记录l,r遍历到了几个元素 int s=1;//记录这一层的区间有几个元素 for(;l^r^1;l>>=1,r>>=1,s<<=1){ if(ln)sumv[l]+=ln*a; if(rn)sumv[r]+=rn*a; if(~l&1)addv[l^1]+=a,ln+=s;//只更新标记啊 if(r&1)addv[r^1]+=a,rn+=s; } data[l]+=ln*a;data[r]+=rn*a; for(ln+=rn,l>>=1;l;l>>=1) data[l]+=ln*a;//我的父亲们~}int query(int l,int r){ l+=m-1,r+=m+1; int sum=0; int ln=0,rn=0; for(int s=1;l^r^1;l>>=1,r>>=1,s<<=1){ if(ln)sum+=addv[l]*ln;//根据标记更新和 if(rn)sum+=addv[r]*rn; if(~l&1)sum+=data[l^1]+addv[l^1]*s,ln+=s; if(r&1)sum+=data[r^1]+addv[r^1]*s,rn+=s; } sum+=addv[l]*ln+addv[r]*rn; for(ln+=rn,l>>=1;l;l>>=1) sum+=addv[l]*ln;//我的父亲们~ return sum;}//PS:有错误就说一说啊。。。
现在,某人又要求造一颗线段树支持 区间修改,区间最小值
还是沿用区间求和的思路,只是代码有点不同
对于更新最小值的操作,不能单纯的加减了,而是要根据儿子的值而修改。
const int maxn=262144;int data[maxn],addv[maxn],m,n;//data是区间最小int query(int l,int r){ int lmax=INT_MAX,rmax=INT_MAX; int s=l+m-1,t=r+m+1; bool _l=false,_r=false; //叶节点不能通过儿子更新,判断是否可以更新 //其实好像下面有更好的判断方式。。。懒得改了 for(;s^t^1;s>>=1,t>>=1){ if(_l)lmax+=addv[s]; if(_r)rmax+=addv[t]; if(~s&1)lmax=min(lmax,data[s^1]+addv[s^1]),_l=true; if(t&1)rmax=min(rmax,data[t^1]+addv[t^1]),_r=true; } lmax+=addv[s];rmax+=addv[t]; lmax=min(lmax,rmax); for(s>>=1;s;s>>=1)lmax+=addv[s]; return lmax;}void add(int l,int r,int a){ int s=l+m-1,t=r+m+1; for(;s^t^1;s>>=1,t>>=1){ if(s<l+m-1)data[s]=min(data[s<<1]+addv[s<<1],data[s<<1|1]+addv[s<<1|1]); if(t<r+m+1)data[t]=min(data[t<<1]+addv[t<<1],data[t<<1|1]+addv[t<<1|1]); if(~s&1)addv[s^1]+=a; if(t&1)addv[t^1]+=a; } data[t]=min(data[t<<1]+addv[t<<1],data[t<<1|1]+addv[t<<1|1]); for(;s;s>>=1) data[s]=min(data[s<<1]+addv[s<<1],data[s<<1|1]+addv[s<<1|1]); }
嘿嘿嘿。。。
我的线段树~
0 0
- ZKW线段树之旅(1)
- zkw线段树 运用
- 【zkw线段树】ural1855
- ZKW线段树
- POJ3468 ZKW线段树
- ZKW线段树
- zkw线段树 模板
- ZKW线段树
- zkw线段树
- zkw线段树
- zkw线段树分析
- ZKW 线段树
- zkw线段树
- zkw线段树详解
- zkw线段树
- poj3468 zkw线段树
- zkw线段树
- zkw线段树
- 《服务的最佳实践》再实践——定时关闭程序
- ijkplayer整理笔记(四)——readThread流程图
- 真机调试解决could not find developer disk image的问题
- Spring3.2.6中事件驱动模型实现原理深入源码分析
- MySQL数据存放位置变动
- ZKW线段树之旅(1)
- 运动检测(前景检测)之(一)ViBe
- hdu5652 India and China Origins(并查集)
- PHP面向对象——clone关键字
- BroadcastReceiver多次unregisterReceiver 导致 Receiver not registered问题
- Bootstrap中的两个容器class
- iOS- 利用AFNetworking(AFN) - 实现图片上传
- 创建smb用户
- JAVA多线程——notify()和notifyAll()的注意事项