cyyz: Day 2 线段树知识整理
Day 2
上午的听课,哎~昏昏欲睡好吧。。
一、扫描线
知识点:
由于多边形千变万化,要想填充多边形内部的所有像素,需要找到一种合适的规则,能够沿着一个方向,一个像素不漏地把多边形内部填满,同时不污染多边形外部。于是我们发明了一条水平方向的扫描线,它从y=0开始,判断与多边形的交点,这些交点把扫描线分成了若干段,我们需要判断哪些段在多边形内部,哪些段在多边形外部,然后把内部的部分着色,完成后,令y=y+1,即扫描线上移一格,重复之前的操作,直到扫描线不再与多边形的任何部分相交。
例题(poj 1151):
代码实现:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=;
double w[N<<];
double x,y,dx,dy,ans;
int n,res=,js; struct edge {
double l,r,h;
int f;
}e[N<<]; struct node {
int l,r,s;
double lc;
}q[N<<]; inline bool cmp(edge a,edge b) {
return a.h<b.h;
} inline void build (int i,int l,int r) {
q[i]=(node){l,r,,};
if(l==r) return;
int mid=(q[i].l+q[i].r)>>;
build(i<<,l,mid);
build(i<<|,mid+,r);
} inline void push_up(int i) {
if(q[i].s) q[i].lc=w[q[i].r+]-w[q[i].l];
else if(q[i].l==q[i].r) q[i].lc=;
else q[i].lc=q[i<<].lc+q[i<<|].lc;
} void up_date(int i,int l,int r,int v) {
if(q[i].l==l && q[i].r==r) {
q[i].s+=v;
push_up(i);
return;
}
int mid=(q[i].l+q[i].r)>>;
if(r<=mid) up_date(i<<,l,r,v);
else if(l>mid) up_date(i<<|,l,r,v);
else up_date(i<<,l,mid,v),up_date(i<<|,mid+,r,v);
push_up(i);
} inline void IU() {
e[js]=(edge) {x,dx,y,};
w[js]=x;
e[js+]=(edge){x,dx,dy,-};
w[js+]=dx;
} int main() {
while (scanf("%d",&n)== && n) {
js=;
for(int i=;i<n;++i) {
scanf("%lf%lf%lf%lf",&x,&y,&dx,&dy);
IU(); js+=;
}
sort(e,e+js,cmp);
sort(w,w+js);
int k=;
for(int i=;i<js;++i)
if(w[i]!=w[i-]) w[k++]=w[i];
build(,,k-);
ans=;
for(int i=;i<js;++i) {
int l=lower_bound(w,w+k,e[i].l)-w;
int r=lower_bound(w,w+k,e[i].r)-w-;
up_date(,l,r,e[i].f);
ans+=(e[i+].h-e[i].h)*q[].lc;
}
printf("Test case #%d\n",++res);
printf("Total explored area: %.2f\n\n",ans);
}
return ;
}
//poj 1151
代码实现
二、线段树(大全)
知识点:
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。线段树至少支持下列操作:
1.Insert(t,x):将包含在区间 int 的元素 x 插入到树t中;
2.Delete(t,x):从线段树 t 中删除元素 x;
3.Search(t,x):返回一个指向树 t 中元素 x 的指针。
线段树代码实现:
#include<iostream>
#include<cstdio>
using namespace std;
const int N=;
int sum[N<<],a[N+];
int n,m,k,L,R; inline int read() {
int n=,f=;char ch=getchar();
while (ch<'' || ch>'') {if(ch=='-') f=-;ch=getchar();}
while (ch<='' && ch>='') {n=(n<<)+(n<<)+ch-'';ch=getchar();}
return n*f;
} inline void push_up(int rt) {
sum[rt]=sum[rt<<]+sum[rt<<|];
} inline void build(int l,int r,int rt) {
if(l==r) {
sum[rt]=a[l];
return ;
}
int m=(l+r)>>;
build(l,m,rt<<),build(m+,r,rt<<|);
push_up(rt);
} inline int query(int L,int R,int l,int r,int rt) {
if(L<=l&&r<=R) return sum[rt];
int s=;
int m=(l+r)>>;
if(L<=m) s+=query(L,R,l,m,rt<<);
if(R>m) s+=query(L,R,m+,r,rt<<|);
return s;
} inline void up_date(int L,int C,int l,int r,int rt) {
if(l==r) {
sum[rt]+=C;
return;
}
int m=(l+r)>>;
if(L<=m) up_date(L,C,l,m,rt<<);
else up_date(L,C,m+,r,rt<<|);
push_up(rt);
} int main() {
n=read();
for(int i=;i<=n;++i) a[i]=read();
build(,n,);
m=read();
for(int i=;i<m;++i) {
k=read(),L=read(),R=read();
if(k==) up_date(L,R,,n,);
if(k==) printf("%d\n",query(L,R,,n,));
}
return ;
}
代码实现
线段树(区间加及求和)代码实现:
#include<iostream>
#include<cstdio>
#define N 1000001
#define ll long long
using namespace std;
ll a[N],ans[N<<],t[N<<];
ll bz,b,c,d,e,f,n,m; inline ll read() {
ll n=,f=;char ch=getchar();
while (ch<''||ch>'') {if(ch=='-') f=-;ch=getchar();}
while (ch<=''&&ch>='') {n=n*+ch-'';ch=getchar();}
return n*f;
} inline void pushup_(ll i) {
ans[i]=ans[i<<]+ans[i<<|];
} inline void build(ll i,ll l,ll r) {
t[i]=;
if(l==r) {
ans[i]=a[l];
return ;
}
ll mid=(l+r)>>;
build(i<<,l,mid);
build(i<<|,mid+,r);
pushup_(i);
} inline void work_(ll i,ll l,ll r,ll k) {
t[i]=t[i]+k;
ans[i]=ans[i]+k*(r-l+);
} inline void push_down(ll i,ll l,ll r) {
ll mid=(l+r)>>;
work_(i<<,l,mid,t[i]);
work_(i<<|,mid+,r,t[i]);
t[i]=;
} inline void _work(ll a,ll b,ll l,ll r,ll i,ll k) {
if(a<=l&&r<=b) {
ans[i]+=k*(r-l+);
t[i]+=k;
return ;
}
push_down(i,l,r);
ll mid=(l+r)>>;
if(a<=mid) _work(a,b,l,mid,i<<,k);
if(b>mid) _work(a,b,mid+,r,i<<|,k);
pushup_(i);
} inline ll query(ll a,ll b,ll l,ll r,ll i) {
ll s=;
if(a<=l&&r<=b) return ans[i];
ll mid=(l+r)>>;
push_down(i,l,r);
if(a<=mid) s+=query(a,b,l,mid,i<<);
if(b>mid) s+=query(a,b,mid+,r,i<<|);
return s;
} int main() {
n=read(),m=read();
for(ll i=;i<=n;++i) a[i]=read();
build(,,n);
while(m--) {
bz=read();
if(bz==) {
b=read(),c=read(),d=read();
_work(b,c,,n,,d);
continue;
}
if(bz==) {
e=read(),f=read();
printf("%lld\n",query(e,f,,n,));
continue;
}
}
return ;
}
代码实现
线段树(区间修改及询问)代码实现:
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e6+;
ll t[N],bz[N],dz[N],L[N],R[N];
int n,m,f,x,y;
ll add; inline int read() {
int n=,f=;char ch=getchar();
while (ch<''||ch>'') {if(ch=='-') f=-;ch=getchar();}
while (ch<=''&&ch>='') {n=n*+ch-'';ch=getchar();}
return n*f;
} inline ll readx() {
ll n=,f=;char ch=getchar();
while (ch<''||ch>'') {if(ch=='-') f=-;ch=getchar();}
while (ch<=''&&ch>='') {n=n*+ch-'';ch=getchar();}
return n*f;
} inline void _work(int i,int l,int r) {
L[i]=l,R[i]=r;
int mid=(l+r)>>;
if(l==r) {
t[i]=dz[l];
return;
}
_work(i<<,l,mid),_work(i<<|,mid+,r);
t[i]=t[i<<]+t[i<<|];
} inline void down_(int i) {
if(bz[i]) {
int mid=(L[i]+R[i])>>;
t[i<<]+=(mid-L[i]+)*bz[i];
t[i<<|]+=(R[i]-mid)*bz[i];
bz[i<<]+=bz[i];
bz[i<<|]+=bz[i];
bz[i]=;
}
} inline void work_(int i,int l,int r,ll add) {
if(L[i]>=l && R[i]<=r) {
t[i]+=(R[i]-L[i]+)*add;
bz[i]+=add;
return;
}
if(L[i]>r || R[i]<l)return;
down_(i);
work_(i<<,l,r,add),work_(i<<|,l,r,add);
t[i]=t[i<<]+t[i<<|];
} inline ll query(int i,int l,int r) {
if(L[i]>=l && R[i]<=r) return t[i];
if(L[i]>r || R[i]<l) return ;
ll s=;
down_(i);
s+=query(i<<,l,r),s+=query(i<<|,l,r);
return s;
} int main() {
n=read();
for(int i=;i<=n;++i) dz[i]=readx();
m=read();
_work(,,n);
for(int i=;i<=m;++i) {
f=read();
switch(f) {
case :
x=read(),y=read(),add=readx();
work_(,x,y,add);
break;
case :
x=read(),y=read();
printf("%lld\n",query(,x,y));
break;
default:
printf("Orz %%%");
break;
}
}
return ;
}
代码实现
线段树(区间加乘及求和)代码实现:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#define ll long long int
using namespace std;
int const N=4e5+; struct Tre {
ll sum, v, bz, l, r;
}e[N]; ll n,m,mod,L,R,val,bz;
ll t[N]; inline ll read() {
ll n=,f=;char ch=getchar();
while (ch<''||ch>'') {if(ch=='-') f=-;ch=getchar();}
while (ch<=''&&ch>='') {n=n*+ch-'';ch=getchar();}
return n*f;
} inline void push_up(ll i) {
e[i].sum=(e[i<<].sum+e[i<<|].sum)%mod;
} inline void build(ll l, ll r, ll i) {
e[i].l=l,e[i].r=r,e[i].bz=;
if(l==r) {
e[i].sum=t[l]%mod;
return;
}
ll mid=(l+r)>>;
build(l,mid,i<<),build(mid+,r,i<<|);
push_up(i);
} inline void pushdown(ll i) {
if(e[i].bz!=) {
e[i<<].v*=e[i].bz; e[i<<|].v*=e[i].bz;
e[i<<].bz*=e[i].bz; e[i<<|].bz*=e[i].bz;
e[i<<].sum*=e[i].bz; e[i<<|].sum*=e[i].bz;
e[i<<].v%=mod; e[i<<|].v%=mod;
e[i<<].bz%=mod; e[i<<|].bz%=mod;
e[i<<].sum%=mod; e[i<<|].sum%=mod;
e[i].bz=;
}
if(e[i].v) {
e[i<<].v+=e[i].v; e[i<<|].v+=e[i].v;
e[i<<].sum+=(e[i<<].r-e[i<<].l+)*e[i].v;
e[i<<|].sum+=(e[i<<|].r-e[i<<|].l+)*e[i].v;
e[i<<].v%=mod; e[i<<|].v%=mod;
e[i<<].sum%=mod; e[i<<|].sum%=mod;
e[i].v=;
}
} inline void work_(ll i) {
if(e[i].l>=L && e[i].r<=R) {
e[i].bz*=val%mod; e[i].bz%=mod;
e[i].v*=val%mod; e[i].v%=mod;
e[i].sum*=val%mod; e[i].sum%=mod;
return;
}
pushdown(i);
ll mid=(e[i].l+e[i].r)>>;
if(L<=mid) work_(i<<);
if(R>mid) work_(i<<|);
push_up(i);
} inline void _work(ll i) {
if(e[i].l>=L && e[i].r<=R) {
e[i].sum+=((e[i].r-e[i].l+)*val)%mod;
e[i].sum%=mod; e[i].v+=val%mod;
e[i].v%=mod;
return;
}
pushdown(i);
ll mid=(e[i].l+e[i].r)>>;
if(L<=mid) _work(i<<);
if(R>mid) _work(i<<|);
push_up(i);
} inline ll query(ll i) {
if(e[i].l>=L && e[i].r<=R) return e[i].sum%mod;
pushdown(i);
ll mid=(e[i].l+e[i].r)>>, ret=;
if(L<=mid) ret=(ret+query(i<<)%mod)%mod;
if(R>mid) ret=(ret+query(i<<|)%mod)%mod;
push_up(i);
return ret%mod;
} int main() {
n=read(),m=read(),mod=read();
for(int i=;i<=n;++i) t[i]=read();
build(,n,);
for(int i=;i<=m;++i) {
bz=read();
if(bz==) {
L=read(),R=read(),val=read();
work_();
} else if(bz==) {
L=read(),R=read(),val=read();
_work();
} else {
L=read(),R=read();
printf("%d\n", query());
}
}
return ;
}
代码实现
线段树(区间修改及询问,单点修改及询问) 代码实现:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#define ll long long int
using namespace std;
int n,m,opt,b,c,x;
const int N=6e5+; struct note {
int l,r,s;
} t[N]; inline int read() {
int n=,f=;char ch=getchar();
while (ch<'' || ch>'') {if(ch=='-') f=-;ch=getchar();}
while (ch<='' && ch>='') {n=(n<<)+(n<<)+ch-'';ch=getchar();}
return n*f;
}
//建树
inline void build(int k,int l,int r) {
int lc=k<<,rc=k<<|;
t[k].l=l,t[k].r=r;
int mid=(l+r)/;
if(l==r) {
t[k].s=read();
return;
}
build(lc,l,mid),build(rc,mid+,r);
t[k].s=t[lc].s+t[rc].s;
}
//单点修改
inline void _change(int k,int p,int v) {
int lc=k<<,rc=k<<|;
int l=t[k].l,r=t[k].r;
if(l==r) {
t[k].s+=v;
return ;
}
int mid=(l+r)>>;
if(p<=mid) _change(lc,p,v);
else _change(rc,p,v);
t[k].s=t[lc].s+t[rc].s;
}
//区间修改
inline void change_(int k,int l,int r,int v) {
int lc=k<<,rc=k<<|;
if(t[k].l==t[k].r) {
t[k].s+=v;
return ;
}
int mid=(t[k].l+t[k].r)>>;
if(l<=mid) change_(lc,l,min(r,mid),v);
if(r>mid) change_(rc,max(l,mid+),r,v);
t[k].s=t[lc].s+t[rc].s;
}
//单点查询
inline int _query(int k,int p) {
int lc=k<<,rc=k<<|;
int l=t[k].l,r=t[k].r;
if(l==r) return t[k].s;
int mid=(l+r)>>;
if(p<=mid) return _query(lc,p);
else return _query(rc,p);
}
//区间查询
inline int query_(int k,int l,int r) {
int lc=k<<,rc=k<<|;
if(t[k].l==l&&t[k].r==r) return t[k].s;
int mid=(t[k].l+t[k].r)>>,ans=;
if(l<=mid) ans+=query_(lc,l,min(r,mid));
if(r>mid) ans+=query_(rc,max(l,mid+),r);
return ans;
} int main() {
n=read();
build(,,n);
m=read();
for(int i=;i<=m;++i) {
opt=read();
if(opt==) {
b=read(),c=read(),x=read();
change_(,b,c,x);
}
if(opt==) {
b=read();
printf("%d\n",_query(,b));
}
if(opt==) {lue...}
if(opt==) {lue...}
}
return ;
}
代码实现
cyyz: Day 2 线段树知识整理的更多相关文章
- Tido c++线段树知识讲解(转载)
线段树知识讲解 定义.建树.单点修改.区间查询 特别声明:如上的讲解说的是区间最大值 如果想要查询区间和 只需要改变一下建树和查询的代码就行了,如下 其他根据自己的需要进行修改即可
- 主席树总结(经典区间第k小问题)(主席树,线段树)
接着上一篇总结--可持久化线段树来整理吧.点击进入 这两种数据结构确实有异曲同工之妙.结构是很相似的,但维护的主要内容并不相同,主席树的离散化.前缀和等思想也要更难理解一些. 闲话 话说刚学习主席树的 ...
- HDU 1754线段树基本操作,建树,更新,查询
代码线段树入门整理中有介绍. #include<cstdio> #include<algorithm> #include<cstring> #include< ...
- 线段树(二)STEP
线段树(二) 线段树例题整理 Part 1:题面 传送门:https://www.luogu.com.cn/problem/P6492(靠之前传送门放错了,暴露了我在机房逛B站的事实-- Part 2 ...
- hdu 1255 覆盖的面积(线段树 面积 交) (待整理)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255 Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. In ...
- hdu Minimum Inversion Number(逆序数的小知识与线段树)
飞! 题解 首先,求逆序数对的思路: 1.得到整个数列后,从前往后扫,统计比a[i]小的,在a[i]后面的有多少个 这样做的话,应该是只有n2的暴力作法,没想到更好的方法 2.统计a[i]前面的,且比 ...
- st表、树状数组与线段树 笔记与思路整理
已更新(2/3):st表.树状数组 st表.树状数组与线段树是三种比较高级的数据结构,大多数操作时间复杂度为O(log n),用来处理一些RMQ问题或类似的数列区间处理问题. 一.ST表(Sparse ...
- HDU 1556 Color the ball(线段树区间更新)
Color the ball 我真的该认真的复习一下以前没懂的知识了,今天看了一下线段树,以前只会用模板,现在看懂了之后,发现还有这么多巧妙的地方,好厉害啊 所以就应该尽量搞懂 弄明白每个知识点 [题 ...
- poj 2528 线段树+离散化
题意:在墙上贴一堆海报(只看横坐标,可以抽象成一线段),新海报可以覆盖旧海报.求最后能看到多少张海报 sol:线段树成段更新.铺第i张海报的时候更新sg[i].x~sg[i].y这一段为i. 然而坐标 ...
随机推荐
- hystrix,request collapser,请求合并
多个商品,需要发送多次网络请求,调用多次接口,才能拿到结果 可以使用HystrixCollapser将多个HystrixCommand合并到一起,多个command放在一个command里面去执行,发 ...
- JBOOT使用总结
@Override public SwAdmin findById(long id) { return DAO.findFirst("SELECT * FROM sw_admin WHERE ...
- UIView与CALayer的区别,很详细(基础教学拓展)转
研究Core Animation已经有段时间了,关于Core Animation,网上没什么好的介绍.苹果网站上有篇专门的总结性介绍,但是似乎原理性的东西不多,看得人云山雾罩,感觉,写那篇东西的人,其 ...
- 如何用JS获取地址栏参数的方法
采用正则表达式获取地址栏参数: 写一个方法来进行正则匹配,同样也可以复用 function GetPar(name) { var reg = new RegExp("(^|&)&qu ...
- Synchronized可重入锁通俗易懂的简单分析
可重入锁概念: 当一个线程得到一个对象锁后,再次请求此对象时时可以再次得到该对象的锁的,这也证明synchronized方法/块的内部调用本类的其他synchronized方法/块时,时永远可以得到锁 ...
- MongoDB 设置参数
服务器配置文件分析 bin目录下的mongod.cfg是服务器的配置文件,文件中主要的配置参数: 1.数据库文件的存放位置 2.服务器日志文件的存放位置 3.默认的IP地址.端口号 设置密码 默认情况 ...
- Django-模型层(单表操作)
目录 1.ORM简介 2.单表操作 2.1创建表 2.2添加表纪录 2.3查询表纪录 2.4删除表纪录 2.5修改表纪录 1.ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了 ...
- OpenStack云计算简介
1. 云计算的发展 云计算是IT技术不断发展的产物. 要理解云计算,需要对IT系统架构的发展过程有所认识. IT系统架构的发展到目前为止大致可以分为3个阶段: 1> 物理机架构 这一阶段,应用部 ...
- ARTS-week6
Algorithm 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数.函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2 Tw ...
- Triton 学习
介绍 Triton 是一款动态二进制分析框架,它支持符号执行和污点分析,同时提供了 pintools 的 python 接口,我们可以使用 python 来使用 pintools 的功能. Trito ...