线段树题

普通的线段树
只是求子结点的最大值
更新节点,区间最值.

基础模板题

线段树区间修改,点修改
区间加减乘除,平方和,根号

HDU1754 I Hate It

传送门
线段树+点修改+区间查询

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define ll long long
using namespace std;
const int maxn=2e5+5;
int A[maxn];
int tree[maxn<<2];
int n,m;
int L,R,C;
void pushup(int rt){
    tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);//因为不是求和,所以直接获取左右结点中大的数
}
void build(int l,int r,int rt){
    if(l==r){
        tree[rt]=A[l];
        return;
    }
    int m=(l+r)>>1;//线段树的平分方式
    build(l,m,rt<<1);//左边,左子结点
    build(m+1,r,rt<<1|1);//右边,右子结点
    pushup(rt);
}
void update(int l,int r,int rt){
    if(l==r){
        tree[rt]=C;
        return;
    }
    int m=(l+r)>>1;
    if(L<=m)update(l,m,rt<<1);//更新在左子树
    else update(m+1,r,rt<<1|1);//更新在右子树
    pushup(rt);//子结点已经更新,该结点也需要更新
}
int query(int l,int r,int rt){
    if(l>=L&&r<=R){
        return tree[rt];
    }
    int m=(l+r)>>1;
    int ans=0;//根据题意更新ans最小值
    if(L<=m)ans=max(ans,query(l,m,rt<<1));
    if(m<R)ans=max(ans,query(m+1,r,rt<<1|1));
    return ans;
}
int main(){
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;i++){
            scanf("%d",&A[i]);
        }
        build(1,n,1);

        for(int i=0; i<m; i++){
            char str[15];
            scanf("%s",str);
            if(str[0]=='Q'){
                scanf("%d%d",&L,&R);
                cout<<query(1,n,1)<<endl;
            }
            else if(str[0]=='U'){
                scanf("%d%d",&L,&C);
                update(1,n,1);
            }
        }
    }
    return 0;
}

优化版
好像快速输入没快多少,还慢了????什么玩意?

#include<iostream>
#include<cstdio>
#include<algorithm>
#define il inline
#define ll int//套了模板,因为原来是long long,懒得改,所以就改define了
#define debug printf("%d %s\n",__LINE__,__FUNCTION__)
#define lson l,m,rt<<1//左儿子
#define rson m+1,r,rt<<1|1//右儿子
using namespace std;
const int N=200005;
ll n,m,sum[N<<2];
ll R,L,C;
il ll read(){//快速读入数字
    char ch=getchar();ll x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
il void pushup(int rt){
    sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
}
il void build(int l,int r,int rt){
    if(l==r){
        sum[rt]=read();
        return;
    }
    int m=(l+r)>>1;
    build(lson),build(rson);
    pushup(rt);
}
il void update(int l,int r,int rt){
    if(l==r){sum[rt]=C;return;}
    ll m=(l+r)>>1;
    if(L<=m)update(lson);//更新在左子树
    else update(rson);//更新在右子树
    pushup(rt);//子结点已经更新,该结点也需要更新
}
il ll query(int l,int r,int rt){
    if(L<=l&&R>=r)return sum[rt];
    int m=(l+r)>>1;
    ll ret=0;
    if(L<=m)ret=max(ret,query(lson));
    if(m<R)ret=max(ret,query(rson));
    return ret;
}
int main(){
    while(~scanf("%d%d",&n,&m)){
        build(1,n,1);
        while(m--){
            char u[3];
            scanf("%s",u);
            if(u[0]=='U'){
                L=read(),C=read();
                update(1,n,1);
            }
            else {
                L=read(),R=read();
                printf("%d\n",query(1,n,1));
            }
        }
    }
    
    return 0;
}

HDU1166 敌兵布阵

传送门
普通线段树,同时实现加,减,最大值操作
线段树+点修改+区间查询

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define ll long long
using namespace std;
const int maxn=2e5+5;
int A[maxn];
int tree[maxn<<2];
int n,m;
int L,R,C;
void pushup(int rt){
    tree[rt]=tree[rt<<1]+tree[rt<<1|1];//因为不是求和,所以直接获取左右结点中大的数
}
void build(int l,int r,int rt){
    if(l==r){
        tree[rt]=A[l];
        return;
    }
    int m=(l+r)>>1;//线段树的平分方式
    build(l,m,rt<<1);//左边,左子结点
    build(m+1,r,rt<<1|1);//右边,右子结点
    pushup(rt);
}
void update(int l,int r,int rt){
    if(l==r){
        tree[rt]+=C;
        return;
    }
    int m=(l+r)>>1;
    if(L<=m)update(l,m,rt<<1);//更新在左子树
    else update(m+1,r,rt<<1|1);//更新在右子树
    pushup(rt);//子结点已经更新,该结点也需要更新
}
int query(int l,int r,int rt){
    if(l>=L&&r<=R){
        return tree[rt];
    }
    int m=(l+r)>>1;
    int ans=0;//根据题意更新ans最小值
    if(L<=m)ans=ans+query(l,m,rt<<1);
    if(m<R)ans=ans+query(m+1,r,rt<<1|1);
    return ans;
}
int main(){
    int t;
    cin>>t;
    for(int j=1;j<=t;j++){

        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&A[i]);
        }

        build(1,n,1);
    //for(int i=1;i<=3*n;i++)printf("%d ",tree[i]);


        printf("Case %d:\n",j);

        while(1){
            char str[15];
            scanf("%s",str);
            if(str[0]=='E')break;
            else if(str[0]=='Q'){
                scanf("%d%d",&L,&R);
                cout<<query(1,n,1)<<endl;
            }else if(str[0]=='A'){
                scanf("%d%d",&L,&C);
                update(1,n,1);
            }else if(str[0]=='S'){
                scanf("%d%d",&L,&C);
                C=-C;
                update(1,n,1);
            }
        }
    }
    return 0;
}

洛谷模板1--区间修改(加)

线段树+区间修改+区间查询
传送门

#include<bits/stdc++.h>
#define il inline
#define ll long long
#define debug printf("%d %s\n",__LINE__,__FUNCTION__)
#define lson l,m,rt<<1//左儿子
#define rson m+1,r,rt<<1|1//右儿子
using namespace std;
const int N=100005;
ll n,m,sum[N<<2],add[N<<2];
ll R,L,C;
il ll read(){//快速读入数字
    ll a=0;char x=getchar();bool f=0;
    while((x<'0'||x>'9')&&x!='-')x=getchar();
    if(x=='-')x=getchar(),f=1;
    while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
    return f?-a:a;
}
il void pushup(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
il void pushdown(int l,int r,int rt){
    ll m=r-l+1;
    if(add[rt]){
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        sum[rt<<1]+=add[rt]*(m-(m>>1));
        sum[rt<<1|1]+=add[rt]*(m>>1);
        add[rt]=0;
    }
}
il void build(int l,int r,int rt){
    add[rt]=0;
    if(l==r){
        sum[rt]=read();
        return;
    }
    int m=l+r>>1;
    build(lson),build(rson);
    pushup(rt);
}
il void update(int l,int r,int rt){
    if(L<=l&&R>=r){
        add[rt]+=C;
        sum[rt]+=(ll)C*(r-l+1);
        return ;
    }
    pushdown(l,r,rt);
    int m=l+r>>1;
    if(L<=m)update(lson);
    if(m<R)update(rson);
    pushup(rt);
}
il ll query(int l,int r,int rt){
    if(L<=l&&R>=r)return sum[rt];
    pushdown(l,r,rt);
    int m=l+r>>1;
    ll ret=0;
    if(L<=m)ret+=query(lson);
    if(m<R)ret+=query(rson);
    return ret;
}
int main(){
    n=read(),m=read();
    build(1,n,1);
    while(m--){
        ll u=read();
        if(u==1){
            L=read(),R=read(),C=read();
            update(1,n,1);
        }
        else {
            L=read(),R=read();
            printf("%lld\n",query(1,n,1));
        }
    }
    return 0;
}

牛客竞赛区间和

传送门
很奇怪,我用之前的模板在hdu里答题都过了,但是在牛客重新套用这个模板竟然过不了?为什么

#include<bits/stdc++.h>
#define il inline
#define ll long long
#define debug printf("%d %s\n",__LINE__,__FUNCTION__)
#define lson l,m,rt<<1//左儿子
#define rson m+1,r,rt<<1|1//右儿子
using namespace std;
const int N=1e6+5;
ll n,m,sum[N<<2],add[N<<2];
ll R,L,C;
il ll read(){//快速读入数字
    ll a=0;char x=getchar();bool f=0;
    while((x<'0'||x>'9')&&x!='-')x=getchar();
    if(x=='-')x=getchar(),f=1;
    while(x>='0'&&x<='9')a=a*10+x-48,x=getchar();
    return f?-a:a;
}
il void pushup(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
il void pushdown(int l,int r,int rt){
    ll m=r-l+1;
    if(add[rt]){
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        sum[rt<<1]+=add[rt]*(m-(m>>1));
        sum[rt<<1|1]+=add[rt]*(m>>1);
        add[rt]=0;
    }
}
il void build(int l,int r,int rt){
    add[rt]=0;
    if(l==r){
        sum[rt]=read();
        return;
    }
    int m=l+r>>1;
    build(lson),build(rson);
    pushup(rt);
}
il void update(int l,int r,int rt){
    if(L<=l&&R>=r){
        add[rt]+=C;
        sum[rt]+=(ll)C*(r-l+1);
        return ;
    }
    pushdown(l,r,rt);
    int m=(l+r)>>1;
    if(L<=m)update(lson);
    if(m<R)update(rson);
    pushup(rt);
}
il ll query(int l,int r,int rt){
    if(L<=l&&R>=r)return sum[rt];
    pushdown(l,r,rt);
    int m=l+r>>1;
    ll ret=0;
    if(L<=m)ret+=query(lson);
    if(m<R)ret+=query(rson);
    return ret;
}
int main(){
    n=read(),m=read();
    build(1,n,1);
    while(m--){
        ll u=read();
        if(u==1){
            L=read(),R=L,C=read();
            update(1,n,1);
        }
        else {
            L=read(),R=read();
            printf("%lld\n",query(1,n,1));
        }
    }
    return 0;
}

洛谷模板2--区间修改(乘)

线段树+区间修改+区间查询
传送门

#include<bits/stdc++.h>
#define LL long long
#define L(x) x<<1    //左儿子 x*2
#define R(x) x<<1|1 //右儿子  x*2+1
const int maxn =1e5+5;
using namespace std;
LL n,m,num[maxn];
LL mod;                     //膜数
inline LL read() {
    LL x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') f=(ch=='-')?-1:1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
    return x*f;
}
struct T {
    LL l,r;
    LL sum,add,mul;
} tree[maxn<<2];//注意开long long 和四倍空间
inline void update(LL p) {
    tree[p].sum=(tree[L(p)].sum+tree[R(p)].sum)%mod;
    return;
}
inline void spread(LL p) {
    LL mid=(tree[p].l+tree[p].r)>>1;
    if(tree[p].mul!=1) {
        tree[L(p)].mul=(tree[L(p)].mul*tree[p].mul)%mod;
        tree[R(p)].mul=(tree[R(p)].mul*tree[p].mul)%mod;
        tree[L(p)].add=(tree[L(p)].add*tree[p].mul)%mod;
        tree[R(p)].add=(tree[R(p)].add*tree[p].mul)%mod;
        tree[L(p)].sum=(tree[L(p)].sum*tree[p].mul)%mod;
        tree[R(p)].sum=(tree[R(p)].sum*tree[p].mul)%mod;
        tree[p].mul=1;
    }
    if(tree[p].add) {
        tree[L(p)].add=(tree[L(p)].add+tree[p].add)%mod;
        tree[R(p)].add=(tree[R(p)].add+tree[p].add)%mod;
        tree[L(p)].sum=(tree[L(p)].sum+tree[p].add*(mid-tree[p].l+1))%mod;
        tree[R(p)].sum=(tree[R(p)].sum+tree[p].add*(tree[p].r-mid))%mod;//tree[p].r-mid不加1
        tree[p].add=0;
    }
    return;
}
inline void build(LL l,LL r,LL p) {//建树
    tree[p].l=l,tree[p].r=r,tree[p].mul=1;
    if(l==r) {
        tree[p].sum=num[l];
        tree[p].mul=1;
        return;
    }
    LL mid=(tree[p].l+tree[p].r)>>1;
    build(l,mid,L(p));
    build(mid+1,r,R(p));
    update(p);
    return;
}
inline void change1(LL l,LL r,LL p,LL v) {//区间增值
    if(tree[p].l==l&&tree[p].r==r) {
        tree[p].add=(tree[p].add+v)%mod;
        tree[p].sum=(tree[p].sum+v*(r-l+1))%mod;
        return;
    }
    spread(p);
    LL mid=(tree[p].l+tree[p].r)>>1;
    if(r<=mid) change1(l,r,L(p),v);
    else if(l>mid) change1(l,r,R(p),v);
    else change1(l,mid,L(p),v),change1(mid+1,r,R(p),v);
    update(p);
    return;
}
inline void change2(LL l,LL r,LL p,LL v) {//区间乘法

    if(tree[p].l==l&&tree[p].r==r) {
        tree[p].mul=(tree[p].mul*v)%mod;
        tree[p].sum=(tree[p].sum*v)%mod;
        tree[p].add=(tree[p].add*v)%mod;
        return;
    }
    spread(p);
    LL mid=(tree[p].l+tree[p].r)>>1;
    if(r<=mid) change2(l,r,L(p),v);
    else if(l>mid) change2(l,r,R(p),v);
    else change2(l,mid,L(p),v),change2(mid+1,r,R(p),v);
    update(p);
    return;
}
inline LL ask_sum1(LL l,LL r,LL p) {//区间和
    if(tree[p].l==l&&tree[p].r==r) {
        return tree[p].sum%mod;
    }
    spread(p);
    LL mid=(tree[p].l+tree[p].r)>>1;
    if(r<=mid) return ask_sum1(l,r,L(p))%mod;
    else if(l>mid) return ask_sum1(l,r,R(p))%mod;
    else  return (ask_sum1(l,mid,L(p))%mod+ask_sum1(mid+1,r,R(p))%mod)%mod;
}

inline LL ask_sum2(LL l,LL r,LL p) {//区间平方和
    if(tree[p].l==tree[p].r) {
        return tree[p].sum*tree[p].sum;
    }
    spread(p);
    LL mid=(tree[p].l+tree[p].r)>>1;
    if(r<=mid) return ask_sum2(l,r,L(p));
    else if(l>mid) return ask_sum2(l,r,R(p));
    else  return ask_sum2(l,mid,L(p))+ask_sum2(mid+1,r,R(p));
}

LL opt,l,r,v;
int main() {
    n=read(),m=read(),mod=read();
    for(int i=1; i<=n; i++) num[i]=read();
    build(1,n,1);
    while(m--) {
        opt=read();
        if(opt==3) {
            l=read(),r=read();
            printf("%lld\n",ask_sum1(l,r,1)%mod);//询问区间和
        }
        if(opt==4) {
            l=read(),r=read();
            printf("%lld\n",ask_sum2(l,r,1)%mod);//询问区间平方和
        }
        if(opt==1) {
            l=read(),r=read(),v=read();
            change2(l,r,1,v);//区间乘
        }
        if(opt==2) {
            l=read(),r=read(),v=read();
            change1(l,r,1,v);//区间加
        }
    }
    return 0;
}

偏序问题

离散化

区间合并

扫描线

离线处理

二维

李超线段树

题目
题目

转载于:https://www.cnblogs.com/Emcikem/p/11413321.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值