线段树
资料:
https://blog.csdn.net/WhereIsHeroFrom/article/details/78969718
https://www.cnblogs.com/cjyyb/p/8567674.html
https://www.cnblogs.com/cjyyb/p/8567721.html
P4145 上帝造题的七分钟2 / 花神游历各国
/*
translation:
第三行一个整数m,表示有m次操作。
k=0表示给[l,r]中的每个数开平方(下取整)
k=1表示询问[l,r]中各个数的和。
数据中有可能l>r所以遇到这种情况请交换l和r。
solution:
唯一的考点,就是在如何取根号上,由于期间信息无法快速更新,所以无法使用延迟标记lazytag
(哦,这太可怕了QAQ),所以大家都注意到了10^9最多开5次就不变了,所以我们可以
考虑每次把修改暴力递归下去,直到当前区间已经全是0或1为止,然后return就好了。
似乎这题目前只有这一种解法,所以说不是非常的新鲜,本题解主要就是记录一种思想和历程,
学习一种结构,一定要搞清楚原理后再回头看看,有时候会柳暗花明又一村
喏 ,code is below.
trigger:
“下去整 ” ,最最重要的优化就是maxx>1才change
区间修改,区间查询,but,无结合律性质
note:
*暴力线段树 ,无法搞lazy_tag ,所以没有pushdown,f的操作
date:
2019.08.15
2019.09.01
*/
#define lson o<<1
#define rson o<<1|1
#define N 1000005
int n,m;
int a[N];
struct tree{
int l,r;
int sum,maxx;//maxx表示最高次幂
}t[N<<2];
inline void pushup(int o){
t[o].sum=t[lson].sum+t[rson].sum;
t[o].maxx=max(t[lson].maxx,t[rson].maxx);
}
inline void build(int l,int r,int o){
t[o].l=l,t[o].r=r;
if(l==r){
t[o].sum=t[o].maxx=a[l];
return ;
}
int mid=t[o].l+t[o].r>>1;
build(l,mid,lson);
build(mid+1,r,rson);
pushup(o);
}
inline void change(int o,int x,int y){
if(t[o].l==t[o].r){
t[o].sum=t[o].maxx=sqrt(t[o].sum);
return ;
}
int mid=t[o].l+t[o].r>>1;
if(x<=mid && t[lson].maxx>1)change(lson,x,y);
if(mid<y && t[rson].maxx>1)change(rson,x,y);
pushup(o);
}
inline int query(int o,int x,int y){
if(x<=t[o].l && t[o].r<=y){
return t[o].sum;
}
int ans=0;
int mid=t[o].l+t[o].r>>1;
if(x<=mid)ans+=query(lson,x,y);
if(mid<y)ans+=query(rson,x,y);
return ans;
}
#undef int
int main(){
#define int long long
freopen("huashen.txt","r",stdin);
rd(n);
rep(i,1,n)rd(a[i]);
build(1,n,1);
rd(m);
while(m--){
int op,l,r;rd(op),rd(l),rd(r);
if(l>r)swap(l,r);
if(op==0)change(1,l,r);
else printf("%d
",query(1,l,r));
}
return 0;
}
线段树1 板子
/*
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
*/
#define lson o<<1
#define rson o<<1|1
#define N 100010
int a[N];
struct tree{
int l,r;
int sum,add;
}t[N<<2];
inline void pushup(int o){t[o].sum=t[lson].sum+t[rson].sum;}
inline void f(int delta,int o){
t[o].add+=delta;
t[o].sum+=delta*(t[o].r-t[o].l+1);
}
inline void pushdown(int o){
if(t[o].add==0)return;
f(t[o].add,lson);
f(t[o].add,rson);
t[o].add=0;
}
inline void update(int o,int x,int y,int k){
if(x<=t[o].l && t[o].r<=y){
f(k,o);
return ;
}
pushdown(o);
int mid=t[o].l+t[o].r>>1;
if(x<=mid)update(lson,x,y,k);
if(mid<y)update(rson,x,y,k);
pushup(o);
}
inline int query(int o,int x,int y){
if(x<=t[o].l && t[o].r<=y){
return t[o].sum;
}
pushdown(o);
int mid=t[o].l+t[o].r>>1;
int ans=0;
if(x<=mid)ans+=query(lson,x,y);
if(mid<y)ans+=query(rson,x,y);
return ans;
}
inline void build(int l,int r,int o){
t[o].l=l,t[o].r=r;
if(l==r){
t[o].sum=a[l];
return ;
}
int mid=l+r>>1;
build(l,mid,lson);
build(mid+1,r,rson);
pushup(o);
}
#undef int
int main(){
#define int long long
//freopen("sgm1.txt","r",stdin);
int n,m;rd(n),rd(m);
rep(i,1,n)rd(a[i]);
build(1,n,1);
while(m--){
char op[3];
int x,y,k;
cin>>op;
if(op[0]=='C'){
rd(x),rd(y),rd(k);
update(1,x,y,k);
}
else if(op[0]=='Q'){
rd(x),rd(y);
printf("%lld
",query(1,x,y));
}
}
return 0;
}
区间最大连续子段和
#define lson o<<1
#define rson o<<1|1
#define N 500001
int max_3(int a,int b,int c){
int d=a;
if(b>d)d=b;
if(c>d)d=c;
return d;
}
struct tree{
int l,r;
int lmax,rmax,sum,dat;
}t[N<<2];
inline void pushup(int o){
t[o].lmax=max_3(t[lson].sum,t[lson].sum+t[rson].lmax,t[lson].lmax);
t[o].rmax=max_3(t[rson].sum,t[rson].sum+t[lson].rmax,t[rson].rmax);
t[o].dat=max_3(t[lson].dat,t[rson].dat,t[lson].rmax+t[rson].lmax);
t[o].sum=t[lson].sum+t[rson].sum;
}
inline void build(int l,int r,int o){
t[o].l=l,t[o].r=r;
if(l==r){
rd(t[o].dat);
t[o].sum=t[o].lmax=t[o].rmax=t[o].dat;
return ;
}
int m=t[o].l+t[o].r>>1;
build(l,m,lson);
build(m+1,r,rson);
pushup(o);
}
inline void change(int o,int x,int v){
if(t[o].l==t[o].r){
t[o].sum=t[o].lmax=t[o].rmax=t[o].dat=v;
return ;
}
int m=t[o].l+t[o].r>>1;
if(x<=m)change(lson,x,v);
else change(rson,x,v);
pushup(o);
}
tree query(int o,int l,int r){
if(t[o].l==l && t[o].r==r){
return t[o];
}
int m=t[o].l+t[o].r>>1;
if(r<=m)return query(lson,l,r);
else if(m<l)return query(rson,l,r);
else{
tree ls=query(lson,l,m);
tree rs=query(rson,m+1,r);
tree ans;
ans.dat=max_3(ls.dat,rs.dat,ls.rmax+rs.lmax);
ans.lmax=max_3(ls.sum,ls.lmax,ls.sum+rs.lmax);
ans.rmax=max_3(rs.sum,rs.rmax,rs.sum+ls.rmax);
ans.sum=ls.sum+rs.sum;
return ans;
}
}
#undef int
int main(){
#define int long long
freopen("CH4301.txt","r",stdin);
int n,m;rd(n),rd(m);
build(1,n,1);
while(m--){
int op,x,y,v;
rd(op);
if(op==1){
rd(x),rd(y);
if(x>y)swap(x,y);
tree ans=query(1,x,y);
printf("%lld
",ans.dat);
}
else{
rd(x),rd(v);
change(1,x,v);
}
}
return 0;
}
/*
题目描述
给定长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:
1、“1 x y”,查询区间 [x,y] 中的最大连续子段和
2、“2 x y”,把 A[x] 改成 y。
对于每个查询指令,输出一个整数表示答案。
第一行两个整数N,M。
第二行N个整数A[i]。
接下来M行每行3个整数k,x,y,k=1表示查询(此时如果x>y,请交换x,y),k=2表示修改。
对于每个查询指令输出一个整数表示答案。
N≤500000,M≤100000
N≤500000,M≤100000
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 3 2
输出样例:
2
-1
sol:
对于一个固定区间,求最大子段和我们有O(n)
的算法。但是如何维护不同区间的LIS
就成了一个问题。我们选择线段树解决区间问题,但使用线段树的话,我们需要明白,维护什么值,以
及如何进行区间操作。
那么我们思考,对于相邻的两个区间,他们的LIS
有几种可能?
1.左侧区间的LIS
2.右侧区间的LIS
3.两个区间合并后,中间新连接的部分
前两点都好理解,针对第三点我们继续思考,中间部分能够成为LIS,其实就是我们从连接部分分别向前向后,获
得一个尽可能大的前/后缀和。那么我们维护或者合并区间的LIS
就需要维护三个值,区间最大子段和,最大前缀和,最大后缀和。而我们在合并区间的时候,如何维护前/后缀和呢?
我们需要多维护一个区间和。
整理我们得到,定义区间ls,rs
合并得到区间d,每个区间维护区间和sum
,区间最大字段和maxs
,区间最大前缀和maxl
,区间最大后缀和maxr
。则合并区间时,可得关系如下
d.sum=ls.sum+rs.sum
d.maxs=max(ls.maxs,rs.maxs,ls.maxr+rs.maxl)
d.maxl=max(ls.maxl,ls.sum+rs.maxl)
d.maxr=max(rs.maxr,rs.sum+ls.maxr)
用线段树维护即可
*/
区间查询最大值,单点修改
/*
reference:
translation:
solution:
trigger:
note:
*
record:
date:
2019.09.01
*/
#define N 200010
#define lson o<<1
#define rson o<<1|1
struct tree{
int l,r;
int maxx;
}t[N<<2];
int n,m;
int a[N];
inline void pushup(int o){
t[o].maxx=max(t[lson].maxx,t[rson].maxx);
}
inline void change(int o,int x,int v){
if(t[o].l==t[o].r){
if(t[o].maxx<v)
t[o].maxx=v;
return ;
}
int mid=t[o].l+t[o].r>>1;
if(x<=mid)change(lson,x,v);//在左子树
else change(rson,x,v);//在右子树
pushup(o);
}
inline void build(int l,int r,int o){
t[o].l=l,t[o].r=r;
if(l==r){
t[o].maxx=a[l];
return;
}
int mid=l+r>>1;
build(l,mid,lson);
build(mid+1,r,rson);
pushup(o);
}
inline int query(int o,int x,int y){
if(x<=t[o].l && t[o].r<=y){
return t[o].maxx;
}
int val=-(1<<30);
int mid=t[o].l+t[o].r>>1;
if(x<=mid)val=max(val,query(lson,x,y));
if(mid<y)val=max(val,query(rson,x,y));
return val;
}
int main(){
#ifdef WIN32
freopen("","r",stdin);
#endif
rd(n),rd(m);
rep(i,1,n)rd(a[i]);
build(1,n,1);
while(m--){
char op[3];int x,y,v;
cin>>op;
if(op[0]=='Q'){
rd(x),rd(y);
printf("%d
",query(1,x,y));
}
else if(op[0]=='U'){
rd(x),rd(v);
change(1,x,v);
}
}
return 0;
}
区间最大公约数
reference:https://www.acwing.com/solution/acwing/content/1047/
#define N 500010
#define lson o<<1
#define rson o<<1|1
struct tree{
int l,r,dat;
}t[N<<2];
int a[N],cf[N],tr[N];
int n,m;
inline void pushup(int o){
t[o].dat=__gcd(t[lson].dat,t[rson].dat);
}
inline void build(int l,int r,int o){
t[o].l=l,t[o].r=r;
if(l==r){
t[o].dat=cf[l];
return ;
}
int mid=l+r>>1;
build(l,mid,lson);
build(mid+1,r,rson);
pushup(o);
}
inline void update(int o,int x,int v){
if(x>n)return ;/////////////////////////////////
if(t[o].l==t[o].r){
t[o].dat+=v;
return ;
}
int mid=(t[o].l+t[o].r)>>1;
if(x<=mid)update(lson,x,v);
else update(rson,x,v);
pushup(o);
}
inline int ask(int o,int x,int y){
if(x>y)return 0;///////////////////////////////////////
if(x<=t[o].l && t[o].r<=y){
return abs(t[o].dat);
}
int mid=t[o].l+t[o].r>>1;
int gcd_l=0,gcd_r=0;
if(x<=mid)gcd_l=ask(lson,x,y);
if(mid<y)gcd_r=ask(rson,x,y);
return abs(__gcd(gcd_l,gcd_r));
}
inline void add(int x, int k){
for(int i=x;i<=n;i+=(-i)&i)
tr[i]+=k;
}
inline int query(int x){
int ans=0;
for(int i=x;i;i-=(-i)&i)
ans+=tr[i];
return ans;
}
#undef int
int main(){
#define int long long
rd(n),rd(m);
rep(i,1,n){
rd(a[i]);
cf[i]=a[i]-a[i-1];
}
build(1,n,1);
while(m--){
int x,y,k;
char op[5];scanf("%s",&op);
if(op[0]=='Q'){
rd(x),rd(y);
printf("%lld
",__gcd(a[x]+query(x),ask(1,x+1,y)));
}
else{
rd(x),rd(y),rd(k);
update(1,x,k);
update(1,y+1,-k);
add(x,k);
add(y+1,-k);
}
}
return 0;
}