zoukankan      html  css  js  c++  java
  • 线段树的板子和题目

    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
  • 相关阅读:
    155. 最小栈
    160. 相交链表
    PAT 1057 Stack
    PAT 1026 Table Tennis
    PAT 1017 Queueing at Bank
    PAT 1014 Waiting in Line
    PAT 1029 Median
    PAT 1016 Phone Bills
    PAT 1010 Radix
    PAT 1122 Hamiltonian Cycle
  • 原文地址:https://www.cnblogs.com/lipu123/p/13920210.html
Copyright © 2011-2022 走看看