• 线段树的板子和题目


    1.单点修改,区间求和

    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+100;
    struct node{
        int l,r;
        ll s;
    }tree[maxn];
    int a[maxn];
    void push_up(int p){
        tree[p].s=tree[p*2].s+tree[p*2+1].s;
    }
    void build(int p,int l,int r){//p为当前节点编号,x,y为区间的左右端点 ,v是权值 
        tree[p].l=l;
        tree[p].r=r;
    /*节点 
                1
            2       3
         4    5   6    7
    */
    /*
                     [1,13]
                     
            [1,7]             [8,13]
            
       [1,4]     [5,7]  [8,10]     [11,13]
       
    [1,2]  [3,4].......  
    
    */ 
    
        if(l==r){
            tree[p].s=a[l];
            return ; 
        }
        int mid=(l+r)/2;
        build(p*2,l,mid);
        build(p*2+1,mid+1,r);
        push_up(p);    
    } 
    void update(int p,int x,int k){
        int L=tree[p].l,R=tree[p].r;
        if(L==R){
            tree[p].s+=k;
            return ;
        }
        if(x<=tree[p*2].r){//左交点 
            update(p*2,x,k);
        }
        else{
            update(p*2+1,x,k);
        }
        push_up(p);
    }
    // l   r
    ll query(int p,int l,int r){
        int L=tree[p].l,R=tree[p].r;
        ll ans=0;
        if(R<l||L>r){
            return 0;
        }
        if(l<=L&&R<=r){
            return tree[p].s;
        }
        if(tree[p*2].r>=l){//当前子左节点 
            ans+=query(p*2,l,r);
        }
        if(tree[p*2+1].l<=r){//当前子右节点 
            ans+=query(p*2+1,l,r);
        }
        return ans;
    }
    int main(){
        int t;
        cin>>t;
        int kase=1;
        while(t--){
            int n;
            cin>>n;
            for(int i=1;i<=n;i++){
                cin>>a[i];
            }
            build(1,1,n);
            printf("Case %d:
    ",kase++);
            char str[10];
            int l,r;
            while(scanf("%s",str)){
                if(str[0]=='E'){
                    break;
                }
                scanf("%d%d",&l,&r);
                if(str[0]=='Q'){
                    ll z=query(1,l,r);
                    printf("%lld
    ",z);
                }
                else if(str[0]=='A'){
                    update(1,l,r);
                }
                else if(str[0]=='S'){
                    update(1,l,-r);
                }
            }
        } 
        return 0;
    } 
    View Code

    2.区间修改,区间求和

    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn=3e6+100;
    struct node{
        ll l,r;
        ll s;
        ll lazy;
    }t[maxn];
    ll a[maxn];
    int n,m;
    void push(int p){
        t[2*p].lazy+=t[p].lazy;//下传标记 
        t[2*p].s+=1ll*(t[2*p].r-t[2*p].l+1)*t[p].lazy;
        
        t[2*p+1].lazy+=t[p].lazy;
        t[2*p+1].s+=1ll*(t[2*p+1].r-t[2*p+1].l+1)*t[p].lazy;
        
        t[p].lazy=0;//还原标记 
    }
    void build(int p,int l,int r){
        t[p].l=l;
        t[p].r=r;
        if(l==r){
            t[p].s=a[l];
            return ;
        }
        int mid=(l+r)/2;
        build(2*p,l,mid);
        build(2*p+1,mid+1,r);
        t[p].s=t[2*p].s+t[2*p+1].s;
    } 
    void update(int p,int l,int r,ll k){
        int L=t[p].l,R=t[p].r;
        if(L>=l&&R<=r){
            t[p].s+=1ll*(R-L+1)*k;
            t[p].lazy+=k;
            return ;
        }
        push(p);
        if(l<=t[2*p].r){
            update(2*p,l,r,k);
        } 
        if(r>=t[2*p+1].l){
            update(2*p+1,l,r,k);
        }
        t[p].s=t[2*p].s+t[2*p+1].s; 
    }
    ll query(int p,int l,int r){ 
        int L=t[p].l,R=t[p].r; 
        if(L>r||R<l){
            return 0; 
        }
        if(l<=L&&r>=R){
            return t[p].s;
        }
        ll ans=0;
        push(p);
        if(l<=t[2*p].r){
            ans+=query(2*p,l,r);
        }
        if(r>=t[2*p+1].l){
            ans+=query(2*p+1,l,r);
        }
        return ans; 
    }
    int main(){
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
        }
        build(1,1,n);
        char str[10];
        int l,r;
        ll k;
        for(int i=1;i<=m;i++){
            scanf("%s",str);
            if(str[0]=='Q'){
                scanf("%d%d",&l,&r); 
                ll ans=query(1,l,r);
                printf("%lld
    ",ans);
            }
            else if(str[0]=='C'){
                scanf("%d%d%lld",&l,&r,&k);
                update(1,l,r,k);
            }
        }
        return 0;
    }
    View Code

    4.区间乘法和加法

    要两个懒惰标记jia,cheng

    当进行乘法操作的时候,加法标记也要乘k,就是+k*jia;

    下传加法标记的时候就是要用(子节点加法标记*父节点的加发标记+父节点的加法标记)

    下传乘法标记的时候就是(子节点的乘法标记*父节点的乘法标记)

    区间和的话就是加法标记*区间长度+子结点的加法标记*夫节点的乘法标记

    下传标记只是为了下一次操作,和区间求和不一样

    void cheng(ll x,ll l,ll r,ll d)
    {
        if (l<=t[x].l&&t[x].r<=r)//全部包括 
    {//三个值全部都要乘上去
    
            t[x].date=t[x].date*d%mod;
            t[x].laze=t[x].laze*d%mod;
            t[x].mul=t[x].mul*d%mod;
        } else
        {
            pushdown(x);//向下传递值 
            ll mid=(t[x].l+t[x].r)/2;
            if (l<=mid) cheng(x*2,l,r,d);//继续往下搜
            if (r>mid)cheng(x*2+1,l,r,d);
            t[x].date=(t[x*2+1].date+t[x*2].date)%mod;//更新sum 
        }
        return;
    }
    void pushdown(ll x)
    {
        t[x*2].laze=(t[x*2].laze*t[x].mul+t[x].laze)%mod;//
        t[x*2+1].laze=(t[x*2+1].laze*t[x].mul+t[x].laze)%mod;
        t[x*2].mul=(t[x*2].mul*t[x].mul)%mod;//
        t[x*2+1].mul=(t[x*2+1].mul*t[x].mul)%mod;
        t[x*2].date=(t[x].laze*(t[x*2].r-t[x*2].l+1)%mod+t[x*2].date*t[x].mul%mod)%mod;//求和 
        t[x*2+1].date=(t[x].laze*(t[x*2+1].r-t[x*2+1].l+1)%mod+t[x*2+1].date*t[x].mul%mod)%mod;//求和 
        t[x].laze=0;t[x].mul=1; 
    }
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<map> 
    #include <math.h>
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+10;
    ll a[maxn]; 
    ll mod;
    inline int read()
    {
        int x=0;char ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x;
    }
    struct node{
        ll l;//l:左节点 r:右节点 
        ll r;//dat:当前节点的值 laze_tag:懒标记,记录改变的值,递归传值 
        ll date,laze;
        ll mul;
    }t[maxn];//四倍n 
    //void f(ll p,ll m,ll k){ 
    //    t[p].laze=(t[p].laze*m+k)%mod;//懒标记传递
    //    t[p].date+=(k*(t[p].r-t[p].l+1))%mod;//当前值加上所有节点总数*值     
    //}
    //void fmul(ll p,ll k){
    //    t[p].mul=(t[p].mul*k)%mod;
    //    t[p].date+=(t[p].date*k)%mod;
    //}
    //void pushdown(ll p){//传懒标 
    //    f(p*2,t[p].mul,t[p].laze);
    //    f(p*2+1,t[p].mul,t[p].laze);
    //    fmul(p*2,t[p].mul);
    //    fmul(p*2+1,t[p].mul);
    //     //将懒标记的值传给下面的左右儿子节点
    //    t[p].laze=0;
    //    t[p].mul=1;
    //    //复原懒标记 
    //}
    void pushdown(ll x)
    {
        t[x*2].laze=(t[x*2].laze*t[x].mul+t[x].laze)%mod;//
        t[x*2+1].laze=(t[x*2+1].laze*t[x].mul+t[x].laze)%mod;
        t[x*2].mul=(t[x*2].mul*t[x].mul)%mod;//
        t[x*2+1].mul=(t[x*2+1].mul*t[x].mul)%mod;
        t[x*2].date=(t[x].laze*(t[x*2].r-t[x*2].l+1)%mod+t[x*2].date*t[x].mul%mod)%mod;//求和 
        t[x*2+1].date=(t[x].laze*(t[x*2+1].r-t[x*2+1].l+1)%mod+t[x*2+1].date*t[x].mul%mod)%mod;//求和 
        t[x].laze=0;t[x].mul=1; 
    }
    void js(ll p,ll l,ll r){//建树 
        t[p].l=l;//记录左右节点 
        t[p].r=r;
        t[p].laze=0; 
        t[p].mul=1;
        if(l==r){//到达底部返回值 
            t[p].date=a[l];
            return ;
        }
        ll mid=(l+r)/2;//中点
        js(p*2,l,mid);
        js(p*2+1,mid+1,r);
            //递归初始化
        t[p].date=(t[p*2].date+t[p*2+1].date)%mod;
          //加上左右儿子节点 
    }
    void pushs(ll p,ll l,ll r,ll v){//区间加减
        if(t[p].l>=l&&t[p].r<=r){//如果区间被包含就修改并打上懒标记 
            t[p].date+=v*(t[p].r-t[p].l+1)%mod;//加上所有值
            t[p].laze+=v%mod;//懒标记修改 
            return ;
        }
        pushdown(p);//查询懒标记,因为下面要递归 
        ll mid=(t[p].l+t[p].r)/2;//取中点
        if(l<=mid){
            pushs(p*2,l,r,v);//修改左边 
        }
        if(r>mid){
            pushs(p*2+1,l,r,v);//修改右边  
        }
        t[p].date=(t[p*2].date+t[p*2+1].date)%mod;//回溯时加上左右儿子节点的值 
    } 
    //void cheng(ll p,ll l,ll r,ll w){
    //    if(l<=t[p].l&&t[p].r<=r){
    //        t[p].date=t[p].date*w%mod;
    //        t[p].laze=t[p].laze*w%mod;
    //        t[p].mul=t[p].mul*w%mod;
    //        return ;
    //    }
    //    pushdown(p);
    //    ll mid=(t[p].l+t[p].r)/2;//取中点
    //    if(l<=mid){
    //        pushs(p*2,l,r,w);//修改左边 
    //    }
    //    if(r>mid){
    //        pushs(p*2+1,l,r,w);//修改右边  
    //    }
    //    t[p].date=(t[p*2].date+t[p*2+1].date)%mod;
    //}
    void cheng(ll x,ll l,ll r,ll d)
    {
        if (l<=t[x].l&&t[x].r<=r)//全部包括 
    {//三个值全部都要乘上去
    
            t[x].date=t[x].date*d%mod;
            t[x].laze=t[x].laze*d%mod;
            t[x].mul=t[x].mul*d%mod;
        } else
        {
            pushdown(x);//向下传递值 
            ll mid=(t[x].l+t[x].r)/2;
            if (l<=mid) cheng(x*2,l,r,d);//继续往下搜
            if (r>mid)cheng(x*2+1,l,r,d);
            t[x].date=(t[x*2+1].date+t[x*2].date)%mod;//更新sum 
        }
        return;
    }
    ll outt(ll p,ll l){//单点查询 
        if(t[p].l==l&&t[p].r==l){//找到目标点就返回 
            return t[p].date%mod;
        }
        pushdown(p);//先回复懒标记的值再传递,因为下面可能递归(要判断是否到了底部,就是这里出了问题QwQ)
        ll mid=(t[p].l+t[p].r)/2;//记录中点
        if(l<=mid) return outt(p*2,l)%mod;//找左边
        if(l>mid) return outt(p*2+1,l)%mod;//找右边 
    }
    ll check(ll p,ll l,ll r,ll x,ll y){
        if(l>=x&&r<=y){
            return t[p].date%mod;
        }
        ll mid=(t[p].l+t[p].r)/2;
        ll ans=0;
        pushdown(p);
        if(x<=mid){
            ans+=check(p*2,l,mid,x,y)%mod; 
        }
        if(mid<y){
            ans+=check(p*2+1,mid+1,r,x,y)%mod;
        }
        return ans%mod;
    } 
    int main(){
        int n,m; 
           cin>>n>>m>>mod;//读入 
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]); 
        js(1,1,n);//建树
        ll z;
        ll x,y,w; 
        for(int i=1;i<=m;i++){
            scanf("%lld",&z);
            if(z==1){
                scanf("%lld%lld%lld",&x,&y,&w);
                cheng(1,x,y,w);
            }
            else if(z==2){
                scanf("%lld%lld%lld",&x,&y,&w);
                pushs(1,x,y,w);
            }
            else if(z==3){
                scanf("%lld%lld",&x,&y);
                ll ans=check(1,1,n,x,y)%mod;
                printf("%lld
    ",ans%mod);
            }
        }
        return 0;//华丽丽的结束,可以A掉树状数组2了!!! 
    }
    完整代码1
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+100;
    int n,m;
    ll mod;
    struct node{
        int l,r;
        ll sum;
        ll lazyj;
        ll lazyc;
    }t[maxn];
    ll a[maxn]; 
    void push_up(int p){
        t[2*p].lazyj=((t[2*p].lazyj*t[p].lazyc)%mod+t[p].lazyj)%mod;
        t[2*p+1].lazyj=((t[2*p+1].lazyj*t[p].lazyc)%mod+t[p].lazyj)%mod;
        
        t[2*p].lazyc=(t[2*p].lazyc*t[p].lazyc)%mod;
        t[2*p+1].lazyc=(t[2*p+1].lazyc*t[p].lazyc)%mod;
        
        t[2*p].sum=(t[p].lazyj*(t[2*p].r-t[2*p].l+1)%mod+(t[2*p].sum*t[p].lazyc)%mod)%mod;
        t[2*p+1].sum=(t[p].lazyj*(t[2*p+1].r-t[2*p+1].l+1)%mod+(t[2*p+1].sum*t[p].lazyc)%mod)%mod;
        
        t[p].lazyj=0;
        t[p].lazyc=1;
        
    }
    void jiafa(int p,int l,int r,ll k){
        int L=t[p].l,R=t[p].r;
        if(L>=l&&R<=r){
            t[p].sum+=k*(t[p].r-t[p].l+1)%mod;
            t[p].lazyj+=k%mod;
            return ;
        }
        push_up(p);
        if(l<=t[2*p].r){
            jiafa(2*p,l,r,k);
        } 
        if(r>=t[2*p+1].l){
            jiafa(2*p+1,l,r,k);
        }
        t[p].sum=(t[2*p].sum+t[2*p+1].sum)%mod;
    }
    void chengfa(int p,int l,int r,ll k){
        int L=t[p].l,R=t[p].r;
        if(L>=l&&R<=r){
            t[p].sum=(t[p].sum*k)%mod;
            t[p].lazyc=(t[p].lazyc*k)%mod;
            t[p].lazyj=(t[p].lazyj*k)%mod; 
            return ;
        }
        push_up(p);
        if(l<=t[2*p].r){
            chengfa(2*p,l,r,k);
        } 
        if(r>=t[2*p+1].l){
            chengfa(2*p+1,l,r,k);
        }
        t[p].sum=(t[2*p].sum+t[2*p+1].sum)%mod;
    }
    void jianshu(int p,int l,int r){
        t[p].l=l,t[p].r=r;    
        t[p].lazyc=1;
        t[p].lazyj=0;
        if(l==r){
            t[p].sum=a[l];
            return ;
        }
        int mid=(l+r)/2;
        jianshu(p*2,l,mid);
        jianshu(p*2+1,mid+1,r);
        t[p].sum=(t[2*p].sum+t[2*p+1].sum)%mod;
    } 
    ll query(int p,int l,int r){
        int L=t[p].l,R=t[p].r;
        if(L>=l&&R<=r){
            return t[p].sum%mod;
        }    
        ll ans=0;
        push_up(p);
        if(l<=t[2*p].r){
            ans+=query(2*p,l,r)%mod;
        }
        if(r>=t[2*p+1].l){
            ans+=query(2*p+1,l,r)%mod;
        }
        return ans%mod;
    }
    int main(){
        cin>>n>>m>>mod;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        jianshu(1,1,n);
        int op,l,r;
        ll k;
        for(int i=1;i<=m;i++){
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d%lld",&l,&r,&k);
                chengfa(1,l,r,k); 
            }
            else if(op==2){
                scanf("%d%d%lld",&l,&r,&k);
                jiafa(1,l,r,k);
            }
            else{
                scanf("%d%d",&l,&r);
                ll ans=query(1,l,r);
                printf("%lld
    ",ans%mod);
            }
        }
        return 0;
    }
    完整代码2

    例题1:

    例题2:就是把区间中的值变成同一个值,这个还带区间加法,区间重赋值,区间求和(就是让区间中的值先乘上0最加上某一个值)

    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+100;
    const int mod=20007; 
    int n,m;
    struct node{
        int l,r;
        ll sum;
        ll lazyj;
        ll lazyc;
    }t[maxn];
    ll a[maxn]; 
    void push_up(int p){
        t[2*p].lazyj=((t[2*p].lazyj*t[p].lazyc)%mod+t[p].lazyj)%mod;
        t[2*p+1].lazyj=((t[2*p+1].lazyj*t[p].lazyc)%mod+t[p].lazyj)%mod;
        
        t[2*p].lazyc=(t[2*p].lazyc*t[p].lazyc)%mod;
        t[2*p+1].lazyc=(t[2*p+1].lazyc*t[p].lazyc)%mod;
        
        t[2*p].sum=(t[p].lazyj*(t[2*p].r-t[2*p].l+1)%mod+(t[2*p].sum*t[p].lazyc)%mod)%mod;
        t[2*p+1].sum=(t[p].lazyj*(t[2*p+1].r-t[2*p+1].l+1)%mod+(t[2*p+1].sum*t[p].lazyc)%mod)%mod;
        
        t[p].lazyj=0;
        t[p].lazyc=1;
        
    }
    void jiafa(int p,int l,int r,ll k){
        int L=t[p].l,R=t[p].r;
        if(L>=l&&R<=r){
            t[p].sum+=k*(t[p].r-t[p].l+1)%mod;
            t[p].lazyj+=k%mod;
            return ;
        }
        push_up(p);
        if(l<=t[2*p].r){
            jiafa(2*p,l,r,k);
        } 
        if(r>=t[2*p+1].l){
            jiafa(2*p+1,l,r,k);
        }
        t[p].sum=(t[2*p].sum+t[2*p+1].sum)%mod;
    }
    void chengfa(int p,int l,int r,ll k){
        int L=t[p].l,R=t[p].r;
        if(L>=l&&R<=r){
            t[p].sum=(t[p].sum*k)%mod;
            t[p].lazyc=(t[p].lazyc*k)%mod;
            t[p].lazyj=(t[p].lazyj*k)%mod; 
            return ;
        }
        push_up(p);
        if(l<=t[2*p].r){
            chengfa(2*p,l,r,k);
        } 
        if(r>=t[2*p+1].l){
            chengfa(2*p+1,l,r,k);
        }
        t[p].sum=(t[2*p].sum+t[2*p+1].sum)%mod;
    }
    void jianshu(int p,int l,int r){
        t[p].l=l,t[p].r=r;    
        t[p].lazyc=1;
        t[p].lazyj=0;
        if(l==r){
            t[p].sum=a[l];
            return ;
        }
        int mid=(l+r)/2;
        jianshu(p*2,l,mid);
        jianshu(p*2+1,mid+1,r);
        t[p].sum=(t[2*p].sum+t[2*p+1].sum)%mod;
    } 
    ll query(int p,int l,int r){
        int L=t[p].l,R=t[p].r;
        if(L>=l&&R<=r){
            return t[p].sum%mod;
        }    
        ll ans=0;
        push_up(p);
        if(l<=t[2*p].r){
            ans+=query(2*p,l,r)%mod;
        }
        if(r>=t[2*p+1].l){
            ans+=query(2*p+1,l,r)%mod;
        }
        return ans%mod;
    }
    int main(){
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            a[i]=0;
        }
        jianshu(1,1,n);
        int op,l,r;
        ll k;
        for(int i=1;i<=m;i++){
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d%lld",&l,&r,&k);
                chengfa(1,l,r,0);
                jiafa(1,l,r,k); 
            }
            else if(op==2){
                scanf("%d%d%lld",&l,&r,&k);
                jiafa(1,l,r,k);
            }
            else{
                scanf("%d%d",&l,&r);
                ll ans1=query(1,l,r); 
                cout<<ans1%mod<<endl;
            } 
        }
        return 0;
    }

    区间重赋值不带区间加法(直接通过改变懒标就行)

    传送门

    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=1e6+100;
    struct node{
        int l,r;
        int dazy;
        int sum;
    }t[maxn];
    void push_up(int p){
        if(t[p].dazy){//必须的 
            t[2*p].dazy=t[p].dazy;
            t[2*p+1].dazy=t[p].dazy;
            t[2*p].sum=(t[2*p].r-t[2*p].l+1)*t[p].dazy;
            t[2*p+1].sum=(t[2*p+1].r-t[2*p+1].l+1)*t[p].dazy;
            t[p].dazy=0;
        }
    }
    void jianshu(int p,int l,int r){
        t[p].l=l;
        t[p].r=r;
        t[p].dazy=0;//注意 
        if(l==r){
            t[p].sum=1;
            return ;    
        }
        int mid=(l+r)/2;
        jianshu(2*p,l,mid);
        jianshu(2*p+1,mid+1,r);
        t[p].sum=t[2*p+1].sum+t[2*p].sum;
    }
    void update(int p,int l,int r,int k){
        int L=t[p].l,R=t[p].r;
        if(L>=l&&R<=r){
            t[p].dazy=k;
            t[p].sum=(R-L+1)*k;
            return ;
        }
        push_up(p);
        if(l<=t[2*p].r){
            update(2*p,l,r,k);
        }
        if(r>=t[2*p+1].l){
            update(2*p+1,l,r,k);
        }
        t[p].sum=t[2*p+1].sum+t[2*p].sum;
    }
    int query(int p,int l,int r){
        int L=t[p].l,R=t[p].r;
        if(L>=l&&R<=r){
            return t[p].sum;
        }
        push_up(p);
        int ans=0;
        if(l<=t[2*p].r){
            ans+=query(2*p,l,r);
        }
        if(r>=t[2*p+1].l){
            ans+=query(2*p+1,l,r);
        }
        return ans;
    }
    int main(){
        int t,n,m;
        scanf("%d",&t);
        int kase=0;
        while(t--){
            scanf("%d%d",&n,&m);
            jianshu(1,1,n);
            int l,r,k;
            for(int i=1;i<=m;i++){
                scanf("%d%d%d",&l,&r,&k);
                update(1,l,r,k);
            }
            int ans=query(1,1,n);
            printf("Case %d: The total value of the hook is %d.
    ",++kase,ans); 
        }
    }
    View Code

    查询区间最大值和最小值(只是查询)

    #include<iostream>
    #include<algorithm>
    #include<math.h> 
    #include<cstring>
    using namespace std;
    const int maxn=1e6+100;
    struct node{
        int l,r;
        int ma,mi;
    }t[maxn];
    int a[maxn];
    int max(int a,int b){
        if(a>b){
            return a;
        }
        return b;
    }
    int min(int a,int b){
        if(a>b){
            return b;
        }
        return a;
    }
    void jianshu(int p,int l,int r){
        t[p].l=l;
        t[p].r=r;
        if(l==r){
            t[p].mi=a[l];
            t[p].ma=a[l];
            return ;
        } 
        int mid=(l+r)/2;
        jianshu(2*p,l,mid);
        jianshu(2*p+1,mid+1,r);
        t[p].ma=max(t[2*p].ma,t[2*p+1].ma);
        t[p].mi=min(t[2*p].mi,t[2*p+1].mi);
    }
    int query1(int p,int l,int r){//最小值 
        int L=t[p].l,R=t[p].r;
        if(L>=l&&R<=r){
            return t[p].mi;
        } 
        if(r<=t[2*p].r){
            return query1(2*p,l,r);
        }
        else if(l>=t[2*p+1].l){
            return query1(2*p+1,l,r);
        }
        else{
            return min(query1(2*p,l,r),query1(2*p+1,l,r));
        }
    }
    int query2(int p,int l,int r){
        int L=t[p].l,R=t[p].r;
        if(L>=l&&R<=r){
            return t[p].ma;
        } 
        if(r<=t[2*p].r){
            return query2(2*p,l,r);
        }
        else if(l>=t[2*p+1].l){
            return query2(2*p+1,l,r);
        }
        else{
            return max(query2(2*p,l,r),query2(2*p+1,l,r));
        }
    }
    int main(){
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        jianshu(1,1,n);
        int l,r;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&l,&r);
            //cout<<query2(1,l,r)<<" "<<query1(1,l,r)<<endl;
            int ans=query2(1,l,r)-query1(1,l,r);
            printf("%d
    ",ans);
        }
    } 
    View Code

    区间最大值(带修改)

    #pragma GCC optimize(1)
    #pragma GCC optimize(2)
    #pragma GCC optimize(3,"Ofast","inline")
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=1e6+100; 
    struct node{
        int l,r;
        int m;
    }t[maxn];
    int a[maxn];
    int n,m;
    void jianshu(int p,int l,int r){
        t[p].l=l;
        t[p].r=r;
        if(l==r){
            t[p].m=a[l];
            return ;
        }
        int mid=(l+r)/2;
        jianshu(2*p,l,mid);
        jianshu(2*p+1,mid+1,r);
        t[p].m=max(t[2*p].m,t[2*p+1].m);
    }
    void update(int p,int pos,int k){
        if(t[p].l==t[p].r){
            t[p].m=k;
            return ;
        }
        if(pos<=t[2*p].r){
            update(2*p,pos,k);
        } 
        else{
            update(2*p+1,pos,k);
        }
        t[p].m=max(t[2*p].m,t[2*p+1].m);
    }
    int query(int p,int l,int r){
        if(l<=t[p].l&&r>=t[p].r){
            return t[p].m;
        } 
        if(r<=t[2*p].r){
            return query(2*p,l,r);
        }
        else if(l>=t[2*p+1].l){
            return query(2*p+1,l,r);
        }
        else{
            return max(query(2*p,l,r),query(2*p+1,l,r));
        }
    }
    int main(){
        while(~scanf("%d%d",&n,&m)){
            char str[10];
            for(int i=1;i<=n;i++){
                cin>>a[i];
            }
            jianshu(1,1,n);
            int l,r;
            int k;
            for(int i=1;i<=m;i++){
                scanf("%s",str);
                if(str[0]=='Q'){
                    scanf("%d%d",&l,&r);
                    int ans=query(1,l,r);
                    printf("%d
    ",ans); 
                }
                else if(str[0]=='U'){
                    scanf("%d%d",&l,&k);
                    update(1,l,k);
                }
            }
        }
    } 
    View Code

    区间开根号

    2^63只需要开 6 次根号就会到 1 . 所以,即使暴力将每个数都更新到 

    #pragma GCC optimize(1)
    #pragma GCC optimize(2)
    #pragma GCC optimize(3,"Ofast","inline")
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    template <typename Tp>
    void read(Tp &x){//read(n);
        x=0;char ch=1;int fh;
        while(ch!='-'&&(ch>'9'||ch<'0')){
            ch=getchar();
        }
        if(ch=='-'){
            fh=-1;ch=getchar();
        }else fh=1;
        while(ch>='0'&&ch<='9'){
            x=(x<<1)+(x<<3)+ch-'0';ch=getchar();
        }
        x*=fh;
    }
    const int maxn=1e6+100; 
    struct node{
        int l,r;
        ll sum;
    }t[maxn];
    ll a[maxn];
    void jianshu(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=(t[p].l+t[p].r)>>1;
        jianshu(p<<1,l,mid);
        jianshu(p<<1|1,mid+1,r);
        t[p].sum=t[p<<1].sum+t[p<<1|1].sum; 
    }
    void update(int p,int l,int r){
        int L=t[p].l,R=t[p].r;
        if(L==R){
            t[p].sum=sqrt(t[p].sum);
            return ;
        } 
        if((R-L+1)>=t[p].sum){//区间内都是1 重点 
            return ;
        } 
        if(l<=t[p<<1].r){
            update(p<<1,l,r);
        } 
        if(r>=t[p<<1|1].l){
            update(p<<1|1,l,r);
        } 
        t[p].sum=t[p<<1].sum+t[p<<1|1].sum; 
    } 
    ll query(int p,int l,int r){
        if(t[p].l>=l&&t[p].r<=r){
            return t[p].sum;
        }
        ll ans=0;
        if(l<=t[p<<1].r){
            ans+=query(p<<1,l,r);
        }
        if(r>=t[p<<1|1].l){
            ans+=query(p<<1|1,l,r);
        }
        return ans;
    }
    int main(){
        int n,m;
        int kase=1;
        while(~scanf("%d",&n)){
            for(int i=1;i<=n;i++){
                scanf("%lld",&a[i]);
            }     
            jianshu(1,1,n);
            scanf("%d",&m); 
            printf("Case #%d:
    ",kase++);
            int op,l,r;
            for(int i=1;i<=m;i++){
                scanf("%d%d%d",&op,&l,&r);
                if(r<l){
                    swap(l,r);
                }            
                if(op==0){
                    update(1,l,r);
                }
                else{
                    printf("%lld
    ",query(1,l,r));
                }
            }
            printf("
    ");
        }
        return 0; 
    } 
    View Code

    dfs序+线段树

    传送门

    题目大意,就是说有一颗树,如果把他的父节点改为一个树,那么他的子节点也会跟着变,为你某一个节点的数

    就是先对这个树求一个dfs序,然后就是线段树的区间修改,和单点查询了

    #include<iostream>
    #include<algorithm>
    #include<cstring> 
    using namespace std;
    const int maxn=1e6+100;
    typedef long long ll;
    template <typename Tp>
    void read(Tp &x){//read(n);
        x=0;char ch=1;int fh;
        while(ch!='-'&&(ch>'9'||ch<'0')){
            ch=getchar();
        }
        if(ch=='-'){
            fh=-1;ch=getchar();
        }else fh=1;
        while(ch>='0'&&ch<='9'){
            x=(x<<1)+(x<<3)+ch-'0';ch=getchar();
        }
        x*=fh;
    }
    inline char read1()//字符串读入挂
    {
        register char ch=getchar();
        while(ch<'A'||ch>'M')ch=getchar();
        return ch;
    }
    struct node{
        int l,r;
        int val;
    }t[maxn]; 
    struct tu{
        int next;
        int to;
    }edge[maxn];
    int head[maxn],cnt;
    int index=0;
    int s[maxn],e[maxn];
    bool vis[maxn];
    void add(int u,int v){
        edge[cnt].to=v;
        edge[cnt].next=head[u];
        head[u]=cnt++;
    }
    void dfs(int u){
        s[u]=++index;
        for(int i=head[u];~i;i=edge[i].next){
            int v=edge[i].to;
            dfs(v);
        }
        e[u]=index;
    }
    void jianshu(int p,int l,int r){
        t[p].l=l;
        t[p].r=r;
        t[p].val=-1;
        if(l==r){
            return ;
        }
        int mid=(t[p].l+t[p].r)/2;
        jianshu(2*p,l,mid);
        jianshu(2*p+1,mid+1,r);
    }
    void push_up(int p){
        if(t[p].val>=0){
            t[2*p].val=t[p].val;
            t[2*p+1].val=t[p].val;
            t[p].val=-1;
        }
    }
    void update(int p,int l,int r,int k){
        if(l<=t[p].l&&t[p].r<=r){
            t[p].val=k;
            return ;
        }
        push_up(p); 
        if(l<=t[2*p].r){
            update(2*p,l,r,k);
        }
        if(r>=t[2*p+1].l){
            update(2*p+1,l,r,k);
        }
    //    if(r<=t[2*p].r){
    //        update(2*p,l,r,k);
    //    } 
    //    else if(l>=t[2*p+1].l){
    //        update(2*p+1,l,r,k);
    //    }
    //    else{
    //        update(2*p,l,r,k);
    //        update(2*p+1,l,r,k);
    //    }
    }
    int query(int p,int x){
        if(t[p].l==t[p].r){
            return t[p].val;
        }
        push_up(p);
        if(x<=t[2*p].r){
            return query(2*p,x);
        } 
        else{
            return query(2*p+1,x);
        }
    }
    int main(){
        int t;
        cin>>t;
        int kase=0;
        while(t--){
            memset(head,-1,sizeof(head));
            memset(vis,false,sizeof vis);
            cnt=0;
            index=0;
            int n;
            cin>>n;
            int u,v;
            for(int i=1;i<=n-1;i++){
                scanf("%d%d",&u,&v);//v是父节点 
                add(v,u);
                vis[u]=true;
            }
            for(int i=1;i<=n;i++){
                if(!vis[i]){
                    dfs(i);
                    break;
                }
            }
            jianshu(1,1,n); 
            char str[10];
            int x,k; 
            int m;
            read(m);
            printf("Case #%d:
    ",++kase);
            for(int i=1;i<=m;i++){
                scanf("%s",str);
                if(str[0]=='C'){
                    scanf("%d",&x);
                    int ans=query(1,s[x]);
                    printf("%d
    ",ans); 
                }
                else if(str[0]=='T'){
                    scanf("%d%d",&x,&k);
                    update(1,s[x],e[x],k);
                }
            }
            
        }
    } 
    View Code

    二分+线段树

    传送门

    参考博客

    有两个操作

    1。选择一个瓶子A,遍历A到n-1(下标是从0开始的)如果遇到瓶子就放一朵花,只到花放完或者没有瓶子了。让你输出放花的

    开始和结束位置,如果没有放花就是出一行字母

    2.就是把A-B中的花都丢弃

    这个题目很巧妙,就是线段树中的sum维护的区间内空瓶子的数量,在一个区间内他是单调的,所以可以二分找这个位置

    而这个懒惰标记有三种状态就是-1(初始状态),

    1标记为1时(把区间内的都清空)因为是t[2*p].sum=(t[2*p].r-t[2*p].l+1)*t[p].flag就都变空了,就是空瓶子为区间长度

    2.标记为0时(区间内的都放满)因为是t[2*p].sum=(t[2*p].r-t[2*p].l+1)*t[p].flag就都变满了,就是区间内的空瓶子为0

    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=1e6+100;
    int n,m;
    struct node{
        int l;
        int r;
        int sum;//区间内空瓶的数量 
        int flag;//如果是-1就是初始状态,不能下传, 
    }t[maxn];
    /*
    1.标记为1时(把区间内的都清空)因为是t[2*p].sum=(t[2*p].r-t[2*p].l+1)*t[p].flag就都变空了,
    就是空瓶子为区间长度
    
    2.标记为0时(区间内的都放满)因为是t[2*p].sum=(t[2*p].r-t[2*p].l+1)*t[p].flag就都变满了,
    就是区间内的空瓶子为0
    */ 
    void build(int p,int l,int r){
        t[p].l=l,t[p].r=r;
        t[p].flag=-1;
        if(l==r){
            t[p].sum=1;
            return ;
        }
        int mid=(t[p].l+t[p].r)/2;
        build(2*p,l,mid);
        build(2*p+1,mid+1,r);
        t[p].sum=t[2*p].sum+t[2*p+1].sum;
    }
    void push_up(int p){
        if(t[p].flag!=-1){
            t[2*p].flag=t[2*p+1].flag=t[p].flag;
            
            t[2*p].sum=(t[2*p].r-t[2*p].l+1)*t[p].flag;
            t[2*p+1].sum=(t[2*p+1].r-t[2*p+1].l+1)*t[p].flag;
            t[p].flag=-1;
        }
    }
    void update(int p,int l,int r,int k){//区间修改 
        int L=t[p].l,R=t[p].r;
        if(l<=L&&r>=R){
            t[p].sum=(R-L+1)*k;
            t[p].flag=k;
            return ;
        }
        push_up(p);
        if(l<=t[2*p].r){
            update(2*p,l,r,k);    
        } 
        if(r>=t[2*p+1].l){
            update(2*p+1,l,r,k);
        } 
        t[p].sum=t[2*p].sum+t[2*p+1].sum;
    } 
    int query(int p,int l,int r){
        int L=t[p].l,R=t[p].r;
        if(l<=L&&r>=R){
            return t[p].sum;
        }
        push_up(p);
        int ans=0;
        if(l<=t[2*p].r){
            ans+=query(2*p,l,r);    
        } 
        if(r>=t[2*p+1].l){
            ans+=query(2*p+1,l,r);
        }  
        return ans;
    }
    int dive(int x,int num){//开始位置和要插花的个数 
        int l=x,r=n;//区间内空瓶子的数量是单调的 
        int ans;//所以能二分 
        while(l<=r){
            int mid=(l+r)/2;
            if(query(1,x,mid)>=num){
                ans=mid;
                r=mid-1;
            }
            else{
                l=mid+1;
            }
        }
        return ans; 
    }
    int main(){
        int kase;
        cin>>kase;
        while(kase--){
            scanf("%d%d",&n,&m);
            int op,l,r;
            build(1,1,n);
            for(int i=1;i<=m;i++){
                scanf("%d",&op);
                if(op==1){
                    int A,F;
                    scanf("%d%d",&A,&F);
                    A++;//序号加一, 
                    int cnt=query(1,A,n);//得到区间[A,n]中空花瓶的个数 
                    if(cnt==0){
                        printf("Can not put any one.
    ");
                    }
                    else{
                        int L=dive(A,1);//二分左端点(第一个能插花的位置)
                        int R=dive(A,min(F,cnt));
                        update(1,L,R,0);//将区间内的花瓶都装满,把flag=0,下传的时候就把子节点的sum变成0了
                        printf("%d %d
    ",L-1,R-1); 
                    }
                }
                else if(op==2){
                    int A,B;
                    scanf("%d%d",&A,&B);
                    A++;
                    B++;
                    printf("%d
    ",B-A+1-query(1,A,B));
                    update(1,A,B,1);
                }
            }
            printf("
    "); 
        }
         
    } 
    View Code
  • 相关阅读:
    开发小技巧: 如何在jQuery中禁用或者启用滚动事件.scroll java程序员
    Spell Checker 新版Chrome的纠错特性 java程序员
    45个漂亮且有创意的HTML5网站展示 java程序员
    70个jquery触摸事件插件——支持手势触摸! java程序员
    40个超酷的jQuery动画教程 java程序员
    极客技术专题【002期】:开发小技巧 如何使用jQuery来处理图片坏链? java程序员
    30个热门的CSS3 Image Hover 脚本 java程序员
    2013年三月GBin1月刊 java程序员
    插入1000万数据的几种优质算法
    批量上传图片(带百分比进度显示)项目源码
  • 原文地址:https://www.cnblogs.com/lipu123/p/13920210.html
Copyright © 2020-2023  润新知