线段树

单点修改区间查询

struct tree{
int l,r;
long long dat;
}t[1000000];
int n,m,a[1000000];
long long inf=0x7fffffff;
void build(int p,int l,int r){
t[p].l=l,t[p].r=r;
if(l==r){t[p].dat=a[l];return;}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
}
void change(int p,int x,int v){
if(t[p].l==t[p].r){t[p].dat=v;return;}
int mid=(t[p].l+t[p].r)/2;
if(x<mid)change(p*2,x,v);
else change(p*2+1,x,v);
t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
}
long long ask(int p,int l,int r){
if(l<=t[p].l&&r>=t[p].r)return t[p].dat;
int mid(t[p].l+t[p].r)/2;
long long val=-inf;
if(l<=mid)val=max(val,ask(p*2,l,r));
if(r>mid)val=max(val,ask(p*2+1,l,r));
return val;
}

例题 i hate it

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct tree{
int l,r;
long long dat;
}t[8000000];
int n,m;long long a[8000000];
int len,w;
long long inf=0x7fffffff;
void build(int p,int l,int r){
t[p].l=l,t[p].r=r;
if(l==r){t[p].dat=a[l];return;}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
}
void change(int p,int x,int v){
if(t[p].l==t[p].r){t[p].dat=v;return;}
int mid=(t[p].l+t[p].r)/2;
if(x<=mid)change(p*2,x,v);
else change(p*2+1,x,v);
t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
}
long long ask(int p,int l,int r){
if(l<=t[p].l&&r>=t[p].r)return t[p].dat;
int mid=(t[p].l+t[p].r)/2;
long long val=-inf;
if(l<=mid)val=max(val,ask(p*2,l,r));
if(r>mid)val=max(val,ask(p*2+1,l,r));
return val;
}
int main(){
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
for(i=1;i<=m;i++)
{
char s[2];
scanf("%s",s);
int p,o;
scanf("%d%d",&p,&o);
if(s[0]=='Q'){
printf("%d
",ask(1,p,o));
}
if(s[0]=='U'){
change(1,p,o);
}
}

return 0;
}

区间修改区间查询 线段树1

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct shu{
int l,r,dat;
long long sum,add;
}t[4000000];
int a[1000000],n,m;
void build(int p,int l,int r){
t[p].l=l,t[p].r=r;
if(l==r){
t[p].sum=a[l];
return;
}
int mid=l+r>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
void spread(int p){
    if(t[p].add){//如果懒标记不为0,就将其下传,修改左右儿子维护的值
        t[p*2].sum+=t[p].add*(t[p*2].r-t[p*2].l+1);
        t[p*2+1].sum+=t[p].add*(t[p*2+1].r-t[p*2+1].l+1);
        t[p*2].add+=t[p].add;//为该节点的左右儿子打上标记
        t[p*2+1].add+=t[p].add;
        t[p].add=0;//下传之后将该节点的懒标记清0
    }
}
void change(int p,int x,int y,int z){
    if(x<=t[p].l && y>=t[p].r){//被覆盖的话,就对其进行修改
        t[p].sum+=(long long)z*(t[p].r-t[p].l+1);
        t[p].add+=z;//打上懒标记
        return;
    }
    spread(p);//如果发现没有被覆盖,那就需要继续向下找,考虑儿子所维护的区间可能因为懒标记的存在而没有修改,因此将懒标记下放
    int mid=t[p].l+t[p].r>>1;
    if(x<=mid) change(p*2,x,y,z);//如果要修改的区间覆盖了左儿子,就修改左儿子
    if(y>mid) change(p*2+1,x,y,z);//右儿子同理
    t[p].sum=t[p*2].sum+t[p*2+1].sum;//最终维护的值等于左儿子的值+右儿子的值   
}
long long ask(int p,int x,int y){
    if(x<=t[p].l && y>=t[p].r) return t[p].sum;//如果被覆盖,就返回维护的值
    spread(p);//下传懒标记,并查询左右儿子
    int mid=t[p].l+t[p].r>>1;
    long long ans=0;
    if(x<=mid) ans+=ask(p*2,x,y);
    if(y>mid) ans+=ask(p*2+1,x,y);//累加答案,返回左右儿子的和
    return ans;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int q,x,y,z;
scanf("%d",&q);
 if(q==1){
     scanf("%d%d%d",&x,&y,&z);
     change(1,x,y,z);
        }
  else {
      scanf("%d%d",&x,&y);
      printf("%lld
",ask(1,x,y));
        }
   }
return 0;
}

最大数

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct tree{
int l,r;
long long dat;
}t[8000000];
int n,m;long long a[8000000];
int len,w;
long long inf=0x7fffffff;
void build(int p,int l,int r){
t[p].l=l,t[p].r=r;
if(l==r){t[p].dat=a[l];return;}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
}
void change(int p,int x,int v){
if(t[p].l==t[p].r){t[p].dat=v;return;}
int mid=(t[p].l+t[p].r)/2;
if(x<=mid)change(p*2,x,v);
else change(p*2+1,x,v);
t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
}
long long ask(int p,int l,int r){
if(l<=t[p].l&&r>=t[p].r)return t[p].dat;
int mid=(t[p].l+t[p].r)/2;
long long val=-inf;
if(l<=mid)val=max(val,ask(p*2,l,r));
if(r>mid)val=max(val,ask(p*2+1,l,r));
return val;
}
int main(){
scanf("%d%d",&n,&m);
memset(a,-inf,sizeof(a));
build(1,1,n);
for(int i=1;i<=n;i++)
{
char s[2];
int q;
scanf("%s",s);
scanf("%d",&q);
if(s[0]=='A'){
q%=m;
w%=m;
q=(q+w)%m;
len++;change(1,len,q);
}
else {
if(q==0){
printf("0");
continue;
}
w=ask(1,len-q+1,len);printf("%d
",w);
}
}
return 0;
}

线段树2 维护序列

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct shu{
int l,r,dat;
long long sum,add,mum;
}t[10000000];
int a[1000000],n,m,mod;
void build(int p,int l,int r){
t[p].l=l,t[p].r=r;t[p].mum=1;
t[p].add=0;
if(l==r){
t[p].sum=a[l];
return;
}
int mid=l+r>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].sum=(t[p*2].sum+t[p*2+1].sum)%mod;
}
void spread(int p){
int mid=(t[p].r+t[p].l)/2;
t[p*2].mum=(t[p*2].mum*t[p].mum)%mod;
t[p*2+1].mum=(t[p*2+1].mum*t[p].mum)%mod;
t[p*2].add=(t[p*2].add*t[p].mum)%mod;
t[p*2+1].add=(t[p*2+1].add*t[p].mum)%mod;
t[p*2].sum=(t[p*2].sum*t[p].mum)%mod;
t[p*2+1].sum=(t[p*2+1].sum*t[p].mum)%mod;
t[p].mum=1;
//先乘再加
t[p*2].add=(t[p*2].add+t[p].add)%mod;
t[p*2+1].add=(t[p*2+1].add+t[p].add)%mod;
t[p*2].sum=(t[p*2].sum+(mid-t[p].l+1)*t[p].add)%mod;
t[p*2+1].sum=(t[p*2+1].sum+(t[p].r-mid)*t[p].add)%mod;
t[p].add=0;
}
/*1.子树的sum、mulv、addv值分别乘上当前节点的mulv值;

2.当前节点的mulv值还原,即置为1;

3.子树的addv值加上当前节点的addv值;

4.子树的sum值加上(子树包含元素数量*当前节点的addv值);

5.当前节点的addv值还原,即置为0。*/
void changesum(int p,int x,int y,int z){
    if(x<=t[p].l && y>=t[p].r){//被覆盖的话,就对其进行修改
        t[p].sum=(t[p].sum+z*(t[p].r-t[p].l+1))%mod;
        t[p].add=(t[p].add+z)%mod;//打上懒标记
        return;
    }
//if(t[p].mum!=1||t[p].add)

    int mid=(t[p].l+t[p].r)>>1;
spread(p);
    if(x<=mid) changesum(p*2,x,y,z);//如果要修改的区间覆盖了左儿子,就修改左儿子
    if(y>mid) changesum(p*2+1,x,y,z);//右儿子同理
    t[p].sum=(t[p*2].sum+t[p*2+1].sum)%mod;//最终维护的值等于左儿子的值+右儿子的值   
}
void changemum(int p,int x,int y,int z){
    if(x<=t[p].l && y>=t[p].r){//被覆盖的话,就对其进行修改
        t[p].sum=(t[p].sum*z)%mod;
        t[p].add=(t[p].add*z)%mod;//打上懒标记
        t[p].mum=(t[p].mum*z)%mod;
        return;
    }
if(t[p].mum!=1||t[p].add)spread(p);
    int mid=t[p].l+t[p].r>>1;
    if(x<=mid) changemum(p*2,x,y,z);//如果要修改的区间覆盖了左儿子,就修改左儿子
    if(y>mid) changemum(p*2+1,x,y,z);//右儿子同理
    t[p].sum=(t[p*2].sum+t[p*2+1].sum)%mod;//最终维护的值等于左儿子的值+右儿子的值   
}

long long ask(int p,int x,int y){
   if(x<=t[p].l && y>=t[p].r) return t[p].sum%mod;//如果被覆盖,就返回维护的值
    int mid=(t[p].l+t[p].r)>>1;
//if(t[p].mum!=1||t[p].add)
spread(p);//下传懒标记,并查询左右儿子
    long long ans=0;
    if(x<=mid) ans+=ask(p*2,x,y);
    if(y>mid) ans+=ask(p*2+1,x,y);//累加答案,返回左右儿子的和
    return ans%mod;
}
int main(){
scanf("%d%d%d",&n,&m,&mod);
for(register int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
for(register int i=1;i<=m;i++){
int a1,a2,a3,a4;
scanf("%d",&a1);
if(a1==1){
scanf("%d%d%d",&a2,&a3,&a4);
changemum(1,a2,a3,a4);
}
if(a1==2){
scanf("%d%d%d",&a2,&a3,&a4);
changesum(1,a2,a3,a4);
}
if(a1==3){
scanf("%d%d",&a2,&a3);
printf("%lld
",ask(1,a2,a3));
}
}
return 0;
}

花神周游列国 开平方暴力修改

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
struct tree{
int l,r;
long long dat,mmax;
}t[1000000];
int n,m;
long long a[1000000];

void build(int p,int l,int r){
t[p].l=l,t[p].r=r;
if(l==r){t[p].dat=t[p].mmax=a[l];return;}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].dat=t[p*2].dat+t[p*2+1].dat;
t[p].mmax=max(t[p*2].mmax,t[p*2+1].mmax);
}
void change(int p,int l,int r){
if(t[p].l==t[p].r){
t[p].dat=sqrt(t[p].dat);
t[p].mmax=t[p].dat;
return;
}
int mid=(t[p].l+t[p].r)/2;
if(l<=mid&&t[p*2].mmax>1)change(p*2,l,r);
if(r>mid&&t[p*2+1].mmax>1)change(p*2+1,l,r);
t[p].dat=t[p*2].dat+t[p*2+1].dat;
t[p].mmax=max(t[p*2].mmax,t[p*2+1].mmax);
}
long long ask(int p,int l,int r){
if(l<=t[p].l&&r>=t[p].r)return t[p].dat;
int mid=(t[p].l+t[p].r)/2;
long long val=0;
if(l<=mid)val+=ask(p*2,l,r);
if(r>mid)val+=ask(p*2+1,l,r);
return val;
}
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#define ll long long
using namespace std;
struct tree{
int l,r;
ll add,sum;
}t[1000000];
int n,c,m;
void build(int p,int l,int r){
t[p].l=l;
t[p].r=r;
t[p].add=0;t[p].sum=1;
if(l==r){
return;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
t[p].sum=t[p*2].sum|t[p*2+1].sum;
}
/*int count(int x){ 
int sum=0;
while(x){
sum+=x%2;
x/=2;
}
return sum;
}
x%2等价于x&1

x/=2==x>>1;
*/
/*int go(int x){
    int sum=1;
    x--;
    while(x)
      sum*=2,x--;
    return sum;
}
sum*=2,x--==1<<sum

*/
void spread(int p){
t[p<<1|1].sum=t[p<<1].sum=t[p].add;
t[p<<1|1].add=t[p<<1].add=t[p].add;
t[p].add=0;
}
void change(int p,int x,int y,int k){
if(x<=t[p].l&&t[p].r<=y){
t[p].sum=k;
t[p].add=k;
return;
}
if(t[p].add)spread(p);
int mid=(t[p].l+t[p].r)>>1;
if(mid>=x)change(p<<1,x,y,k);
if(mid<y)change(p<<1|1,x,y,k);
t[p].sum=t[p<<1].sum|t[p<<1|1].sum;
}//乘法标记是*=,加法标记是+=,赋值标记是=
ll ask(int p,int x,int y){
if(x<=t[p].l&&t[p].r<=y)return t[p].sum;
if(t[p].add)spread(p);
int mid=(t[p].l+t[p].r)>>1; 
long long ans=0;
if(mid>=x)ans=ans|ask(p<<1,x,y);
if(mid<y)ans=ans|ask(p<<1|1,x,y);
return ans;
}
int main(){
scanf("%d%d%d",&n,&c,&m);
build(1,1,n);
while(m--){
char s[2];
int a1,a2,a3;
scanf("%s",s);
if(s[0]=='C'){
scanf("%d%d%d",&a1,&a2,&a3);
if(a1>a2)swap(a1,a2);
change(1,a1,a2,1<<a3-1);
}
else {
scanf("%d%d",&a1,&a2);
if(a1>a2)swap(a1,a2);
ll num=ask(1,a1,a2);
ll ans=0;
for(int i=0;i<=c;i++)if(num&(1<<i))ans++;//表示若序列中有这种颜色
//注意i=0,因为要考虑=1情况
printf("%lld
",ans);
}
}
return 0;
}


int main(){
scanf("%d",&n);
for(register int i=1;i<=n;i++)
scanf("%lld",&a[i]);
build(1,1,n);
scanf("%d",&m);
for(register int i=1;i<=m;i++){
int a1,a2,a3;
scanf("%d%d%d",&a1,&a2,&a3);
if(a2>a3)swap(a2,a3);
if(!a1)change(1,a2,a3);
else printf("%lld
",ask(1,a2,a3));
}
return 0;
}

色板游戏

缘分让我们相遇乱世以外, 命运却要我们危难中相爱。 也许未来遥远在光年之外, 我愿守候未知里为你等待。
原文地址:https://www.cnblogs.com/zw130-lzr-blogs/p/10964434.html