[模板]线段树

修改儿子之前pushdown,修改儿子之后update,查询儿子之前pushdown,多种操作理清楚先后顺序

经测试inline基本没用

注意避免中间结果爆int

数组开N*4

多种操作可以尽量合成一个函数,减少代码量

 

EOJ 3393

区间求和、最大值、最小值 支持区间加法和区间覆盖

#include<bits/stdc++.h>
using namespace std;
#define LL long long 
#define rep(i,n) for(int i=1;i<=n;i++)
#define pLL pair<long long,long long>
#define st first 
#define nd second
#define mp make_pair

const int N=5e5+7;
const LL inf=7e18;

int n,q;

int a[N];

LL tree[N*4][3];
LL tag1[N*4],tag2[N*4];
int len[N*4];

inline LL max(LL x,LL y){
    if(x>y)return x;
    return y;
}

inline LL min(LL x,LL y){
    if(x<y)return x;
    return y;
}

inline void update(int node){
    tree[node][0]=tree[node<<1][0]+tree[node<<1^1][0];
    tree[node][1]=max(tree[node<<1][1],tree[node<<1^1][1]);
    tree[node][2]=min(tree[node<<1][2],tree[node<<1^1][2]);
}

void build(int node,int l,int r){
    tag1[node]=tag2[node]=inf;
    len[node]=r-l+1;
    if(l==r){
        tree[node][0]=tree[node][1]=tree[node][2]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(node<<1,l,mid);
    build(node<<1^1,mid+1,r);
    update(node);
}

inline pair<LL,pLL> merge(pair<LL,pLL> a,pair<LL,pLL> b){
    return mp(a.st+b.st,mp( max(a.nd.st,b.nd.st) , min(a.nd.nd,b.nd.nd) ) );
}

inline void maketag(int node,LL a,LL b){
    if(b!=inf){
        tree[node][0]=b*len[node];
        tree[node][1]=b;
        tree[node][2]=b;
        tag1[node]=inf;
        tag2[node]=b;
    }
        if(a!=inf){
        tree[node][0]+=a*len[node];
        tree[node][1]+=a;
        tree[node][2]+=a;
        if(tag1[node]==inf)tag1[node]=0;
        tag1[node]+=a;
        }
}

inline void pushdown(int node){
   maketag(node<<1,tag1[node],tag2[node]);
   maketag(node<<1^1,tag1[node],tag2[node]);
   tag1[node]=tag2[node]=inf; 
}

inline void change(int node,int L,int R,int l,int r,LL a,LL b){
    if(R<l||L>r)return ;
    if(L>=l&&R<=r){
        maketag(node,a,b);
        return ;
    }
    if(tag1[node]!=inf||tag2[node]!=inf)pushdown(node);
    int mid=(L+R)>>1;
    change(node<<1,L,mid,l,r,a,b);
    change(node<<1^1,mid+1,R,l,r,a,b);
    update(node); 
}

inline pair<LL,pLL> query(int node,int L,int R,int l,int r){
    if(R<l||L>r)return mp(0,mp(-inf,inf));
    if(L>=l&&R<=r){
        return mp(tree[node][0],mp(tree[node][1],tree[node][2]));
    }
    int mid=(L+R)>>1;
    pushdown(node);
    return merge(query(node<<1,L,mid,l,r),query(node<<1^1,mid+1,R,l,r));
}

int main(){
    scanf("%d",&n);
    rep(i,n)scanf("%d",&a[i]);
    
    build(1,1,n);

    scanf("%d",&q);
    while(q--){
        int f,l,r;
        scanf("%d%d%d",&f,&l,&r);
        if(f==3){
            pair<LL,pLL> ans=query(1,1,n,l,r);
            printf("%lld %lld %lld\n",ans.st,ans.nd.st,ans.nd.nd);
        }
        if(f==1){
            int v;
            scanf("%d",&v);
            change(1,1,n,l,r,v,inf);
        }
        if(f==2){
            int v;
            scanf("%d",&v);
            change(1,1,n,l,r,inf,v);
        }
    }
}
View Code

 

ZOJ 3998

区间求积 支持区间乘法和区间求幂

乘方的取模利用费马小定理的推论:a^n ≡ a^ (n mod φ(p))(modp),p为质数时φ(p)=p-1。其他基本和上一题相同。

快速幂不要用递归!!!

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,n) for(int i=1;i<=n;i++)

const int N=1e5+7;
const int mod=1e9+7;

int n,a[N],tree[N*4],tag1[N*4],tag2[N*4],len[N*4];

inline void update(int node){
    tree[node]=1LL*tree[node<<1]*tree[node<<1|1]%mod;
}

inline int po(int x,int y){
    int res=1;
      while(y){
      if(y&1)res=1LL*res*x%mod;
      y>>=1;
      x=1LL*x*x%mod;
      }
      return res;
}

inline void maketag(int node,int v,int k){
    tree[node]=1LL*po(tree[node],k)*po(v,len[node])%mod;
    tag1[node]=1LL*po(tag1[node],k)*v%mod;
    tag2[node]=1LL*tag2[node]*k%(mod-1);
}

inline void push_down(int node){
    maketag(node<<1,tag1[node],tag2[node]);
    maketag(node<<1|1,tag1[node],tag2[node]);
    tag1[node]=tag2[node]=1;
}

inline int query(int node,int L,int R,int l,int r){
    if(l>R||r<L)return 1; 
    if(L>=l&&R<=r)return tree[node];
    push_down(node);
    int mid=(L+R)>>1;
    return 1LL*query(node<<1,L,mid,l,r)*query(node<<1|1,mid+1,R,l,r)%mod;
}

inline void change(int node,int L,int R,int l,int r,int v,int k){
    if(l>R||r<L)return;
    if(L>=l&&R<=r){
        maketag(node,v,k);
        return ;
    }
    if(tag1[node]!=1||tag2[node]!=1)push_down(node);
    int mid=(L+R)>>1;
    change(node<<1,L,mid,l,r,v,k);
    change(node<<1|1,mid+1,R,l,r,v,k);
    update(node);
}

void build(int node,int l,int r){
    tag1[node]=tag2[node]=1;
    len[node]=r-l+1;
    if(l==r){
        tree[node]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(node<<1,l,mid);
    build(node<<1|1,mid+1,r);
    update(node);
}

int main()
{
    int t,q;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&q);

        rep(i,n)scanf("%d",&a[i]);

        build(1,1,n);

        while(q--){
            int op,l,r,v;
            scanf("%d%d%d",&op,&l,&r);
            if(op==1){
                scanf("%d",&v);
                change(1,1,n,l,r,v,1);
            }
            if(op==2){
                scanf("%d",&v);
                change(1,1,n,l,r,1,v);
            }
            if(op==3){
                printf("%d\n",query(1,1,n,l,r));
            }
        }
    }
    //system("pause");
}
View Code

 

洛谷 3373

区间求和 支持区间加法和区间乘法

#include<bits/stdc++.h>
using namespace std;
#define LL long long 
#define rep(i,n) for(int i=1;i<=n;i++)
#define pLL pair<long long,long long>
#define st first 
#define nd second
#define mp make_pair

const int N=1e5+7;
const LL inf=7e18;

int n,q;

int a[N];

LL tree[N*4],add[N*4],mul[N*4],len[N*4],p;

void update(int node){
    tree[node]=(tree[node<<1]+tree[node<<1^1])%p;
}

void build(int node,int l,int r){
    add[node]=0;
    mul[node]=1;
    len[node]=r-l+1;
    if(l==r){
        tree[node]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(node<<1,l,mid);
    build(node<<1^1,mid+1,r);
    update(node);
}

void maketag(int node,LL a,LL b){
    tree[node]=(a*tree[node]%p + b*len[node]%p)%p;
    add[node]=(a*add[node]%p + b )%p;
    mul[node]=mul[node]*a%p;
}

void pushdown(int node){
    maketag(node<<1,mul[node],add[node]);
    maketag(node<<1^1,mul[node],add[node]);
    mul[node]=1;
    add[node]=0;
}

void change(int node,int L,int R,int l,int r,LL a,LL b){
    if(R<l||L>r)return ;
    if(L>=l&&R<=r){
        maketag(node,a,b);
        return;
    }
    int mid=(L+R)>>1;
    pushdown(node);
    change(node<<1,L,mid,l,r,a,b);
    change(node<<1^1,mid+1,R,l,r,a,b);
    update(node);
}

LL query(int node,int L,int R,int l,int r){
    if(R<l||L>r)return 0;
    if(L>=l&&R<=r)return tree[node];
    pushdown(node);
    int mid=(L+R)>>1;
    return    (query(node<<1,L,mid,l,r)+query(node<<1^1,mid+1,R,l,r))%p;
}

int main(){
    scanf("%d%d%d",&n,&q,&p);
    rep(i,n)scanf("%d",&a[i]);
    
    build(1,1,n);
    
    while(q--){
        int f,l,r;
        scanf("%d%d%d",&f,&l,&r);
        if(f==3){
            printf("%lld\n",query(1,1,n,l,r));
        }
        if(f==2){
            int v;
            scanf("%d",&v);
            change(1,1,n,l,r,1,v);
        }
        if(f==1){
            int v;
            scanf("%d",&v);
            change(1,1,n,l,r,v,0);
        }
    }
}
View Code

 

转载于:https://www.cnblogs.com/xutianshu/p/10616825.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值