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 线段树知识整理的更多相关文章

  1. Tido c++线段树知识讲解(转载)

    线段树知识讲解 定义.建树.单点修改.区间查询         特别声明:如上的讲解说的是区间最大值 如果想要查询区间和 只需要改变一下建树和查询的代码就行了,如下 其他根据自己的需要进行修改即可

  2. 主席树总结(经典区间第k小问题)(主席树,线段树)

    接着上一篇总结--可持久化线段树来整理吧.点击进入 这两种数据结构确实有异曲同工之妙.结构是很相似的,但维护的主要内容并不相同,主席树的离散化.前缀和等思想也要更难理解一些. 闲话 话说刚学习主席树的 ...

  3. HDU 1754线段树基本操作,建树,更新,查询

    代码线段树入门整理中有介绍. #include<cstdio> #include<algorithm> #include<cstring> #include< ...

  4. 线段树(二)STEP

    线段树(二) 线段树例题整理 Part 1:题面 传送门:https://www.luogu.com.cn/problem/P6492(靠之前传送门放错了,暴露了我在机房逛B站的事实-- Part 2 ...

  5. hdu 1255 覆盖的面积(线段树 面积 交) (待整理)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255 Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.   In ...

  6. hdu Minimum Inversion Number(逆序数的小知识与线段树)

    飞! 题解 首先,求逆序数对的思路: 1.得到整个数列后,从前往后扫,统计比a[i]小的,在a[i]后面的有多少个 这样做的话,应该是只有n2的暴力作法,没想到更好的方法 2.统计a[i]前面的,且比 ...

  7. st表、树状数组与线段树 笔记与思路整理

    已更新(2/3):st表.树状数组 st表.树状数组与线段树是三种比较高级的数据结构,大多数操作时间复杂度为O(log n),用来处理一些RMQ问题或类似的数列区间处理问题. 一.ST表(Sparse ...

  8. HDU 1556 Color the ball(线段树区间更新)

    Color the ball 我真的该认真的复习一下以前没懂的知识了,今天看了一下线段树,以前只会用模板,现在看懂了之后,发现还有这么多巧妙的地方,好厉害啊 所以就应该尽量搞懂 弄明白每个知识点 [题 ...

  9. poj 2528 线段树+离散化

    题意:在墙上贴一堆海报(只看横坐标,可以抽象成一线段),新海报可以覆盖旧海报.求最后能看到多少张海报 sol:线段树成段更新.铺第i张海报的时候更新sg[i].x~sg[i].y这一段为i. 然而坐标 ...

随机推荐

  1. 【已解决】ArcMap的界面如何恢复默认设置

    解决方案:在C盘内搜索“Normal.mxt”,将它删除,然后重启ArcMap,即可.  效果图:

  2. Mysql中use filesort的误区

    误区一字面误区 use filesort排序,字面上理解是外部排序. 误区二人云亦云 百度上多被大家否定不是外部排序,认为和file这个关键字没关系.用的是快速排序.但是总觉得不可能这么无缘无故叫fi ...

  3. Matlab装饰模式

    装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.根据https://www.runoob.com/design-pattern/decorator ...

  4. 【开发笔记】- 永远不要在MySQL中使用UTF-8

    原文地址:https://mp.weixin.qq.com/s/I3Tkvn8vSyC5lEpD9HzwiA 最近我遇到了一个bug,我试着通过Rails在以“utf8”编码的MariaDB中保存一个 ...

  5. TypeScript编写Vue项目结构解析

    使用TypeScript编写Vue项目也已经有了一段时间,笔者在刚刚使用TypeScript时候也是很茫然,不知道从何下手,感觉使用TypeScript写项目感觉很累赘并不像JavaScript那么灵 ...

  6. ABAP-System Functions

    ABAP_CALLSTACK ABAP_CRC64 ABAP_PRECOMPILED_HEADER_USAGE ABSTOR_TEST AB_CALL_LITL_CHECK AB_CALL_STACK ...

  7. 多代理切换 MultiProxy

    配置代理选项 添加代理列表 ie配置代理 开始使用

  8. ipc$ 空连接 net use

    常用命令 [xxx]表示的内容,需要根据自己的需求更改 //建立空连接 > net use \\127.0.0.1\ipc$ //删除连接 > net use \\127.0.0.1\ip ...

  9. MySQL Processlist--查看会话执行过的SQL情况

    对于MySQL 5.7版本,可以使用sys.session视图来查看会话最后一次执行的SQL: SELECT * FROM sys.session WHERE CONN_ID = \G 其中sys.s ...

  10. Xshell6和Xftp6 破解免安装版,无窗口多开限制

    免安装无窗口限制破解版 链接:https://pan.baidu.com/s/1wpFE499qoTjqHrPdQmTn4g提取码:2xcn 如上面的链接失效,可使用以下的链接: https://pa ...