zoukankan      html  css  js  c++  java
  • 线段树题目乱堆

    题意

    范围$1e18$

    题解

    首先看到范围这么大,肯定要离散化的,

    发现最后最左面0位置只可能修改过的位置-1,+1,等,不可能在一段区间中间凭空出现

    于是可以这样离散化

            if(l[i]!=1)
                lsh[++lsh[0]]=l[i]-1;
            lsh[++lsh[0]]=l[i];
            lsh[++lsh[0]]=r[i];
            lsh[++lsh[0]]=r[i]+1;

    然后考虑如何维护

    两种方法:

    1.维护最左0出现位置,最左1出现位置

    这样异或操作就swap一下就好了

    我没打这种

    2.维护区间0个数,

    这样异或操作就转化成了区间长度-0个数

    查询如果左子树有0优先走左子树,否则走右子树,递归到叶子

    3.keduoli树水过

    这里用的第2种方法

    两种懒标记不可同时存在,

    down

    void down(ll x){
    //    printf("l=%lld r=%lld tr[lson].f1=%lld tr[rson].f1=%lld
    ",tr[x].l,tr[x].r,tr[x<<1].f1,tr[x<<1|1].f1);
        if(tr[x].f1){
            if(tr[x<<1].f2){
                tr[x<<1].f2=0;
                tr[x<<1].sum=tr[x<<1].len-tr[x<<1].sum;
            }
            if(tr[x<<1|1].f2){
                tr[x<<1|1].f2=0;
                tr[x<<1|1].sum=tr[x<<1|1].len-tr[x<<1|1].sum;
            }
            tr[x<<1].f1=tr[x].f1;
            tr[x<<1].sum=((tr[x].f1==2)?tr[x<<1].len:0);
            tr[x<<1|1].f1=tr[x].f1;
            tr[x<<1|1].sum=((tr[x].f1==2)?tr[x<<1|1].len:0);
        }
        else if(tr[x].f2){//区间异或
            if(tr[x<<1].f2){
                tr[x<<1].f2=0;
                tr[x<<1].sum=tr[x<<1].len-tr[x<<1].sum;
            }
            else if(tr[x<<1].f1==1){
                tr[x<<1].sum=tr[x<<1].len;
                tr[x<<1].f1=2;
                tr[x<<1].f2=0;
            }
            else if(tr[x<<1].f1==2){
                tr[x<<1].sum=0;
                tr[x<<1].f1=1;
                tr[x<<1].f2=0;
            }
            else tr[x<<1].f2=1,tr[x<<1].sum=tr[x<<1].len-tr[x<<1].sum;
            if(tr[x<<1|1].f2){
                tr[x<<1|1].f2=0;
                tr[x<<1|1].sum=tr[x<<1|1].len-tr[x<<1|1].sum;
            }
            else if(tr[x<<1|1].f1==1){
                tr[x<<1|1].sum=tr[x<<1|1].len;
                tr[x<<1|1].f1=2;
                tr[x<<1|1].f2=0;
            }
            else if(tr[x<<1|1].f1==2){
                tr[x<<1|1].sum=0;
                tr[x<<1|1].f1=1;
                tr[x<<1|1].f2=0;
            }
            else tr[x<<1|1].f2=1,tr[x<<1|1].sum=tr[x<<1|1].len-tr[x<<1|1].sum;
        }    
    //    printf("down*** f1=%lld f2=%lld lson.f2=%lld rson.f2=%lld  l=%lld r=%lld tr[x].sum=%lld lson l=%lld r=%lld sum=%lld rson l=%lld r=%lld sum=%lld
    ",tr[x].f1,tr[x].f2,tr[x<<1].f2,tr[x<<1|1].f2,tr[x].l,tr[x].r,tr[x].sum,tr[x<<1].l,tr[x<<1].r,tr[x<<1].sum,tr[x<<1|1].l,tr[x<<1|1].r,tr[x<<1|1].sum);
    //    printf("l=%lld r=%lld lson.f1=%lld f2=%lld sum=%lld l=%lld r=%lld rson.f1=%lld f2=%lld sum=%lld
    ",tr[x<<1].l,tr[x<<1].r,tr[x<<1].f1,tr[x<<1].f2,tr[x<<1].sum,tr[x<<1|1].l,tr[x<<1|1].r,tr[x<<1|1].f1,tr[x<<1|1].f2,tr[x<<1|1].sum);
        tr[x].f1=0;
        tr[x].f2=0;
    
    }

    注意,这里区间修改因为两种懒标记不可同时存在,所以也要进行这种操作

    可能两次都修改同一个区间,这样你上一个标记没下传,这一个标记就又来了

    特殊处理一下

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define A 10010101
    ll c[A],l[A],r[A],opt[A],now[A],lsh[A],yuan[A];
    ll ans,canqj=1,rest,n,len;
    struct node{
        ll l,r,f1,f2,len,sum,yu;
    }tr[A];
    void up(ll x){
        tr[x].sum=tr[x<<1].sum+tr[x<<1|1].sum;
    //    printf("x.l=%lld x.r=%lld tr[x].sum=%lld
    ",tr[x].l,tr[x].r,tr[x].sum);
    }
    void built(ll x,ll l,ll r){
        tr[x].l=l,tr[x].r=r;
        tr[x].len=r-l+1;
        if(l==r){
            tr[x].sum=1;
            tr[x].yu=lsh[l];
            return;
        }
        ll mid=(tr[x].l+tr[x].r)>>1;
        built(x<<1,l,mid);
        built(x<<1|1,mid+1,r);
        up(x);
    }
    void down(ll x){
    //    printf("l=%lld r=%lld tr[lson].f1=%lld tr[rson].f1=%lld
    ",tr[x].l,tr[x].r,tr[x<<1].f1,tr[x<<1|1].f1);
        if(tr[x].f1){
            if(tr[x<<1].f2){
                tr[x<<1].f2=0;
                tr[x<<1].sum=tr[x<<1].len-tr[x<<1].sum;
            }
            if(tr[x<<1|1].f2){
                tr[x<<1|1].f2=0;
                tr[x<<1|1].sum=tr[x<<1|1].len-tr[x<<1|1].sum;
            }
            tr[x<<1].f1=tr[x].f1;
            tr[x<<1].sum=((tr[x].f1==2)?tr[x<<1].len:0);
            tr[x<<1|1].f1=tr[x].f1;
            tr[x<<1|1].sum=((tr[x].f1==2)?tr[x<<1|1].len:0);
        }
        else if(tr[x].f2){//区间异或
            if(tr[x<<1].f2){
                tr[x<<1].f2=0;
                tr[x<<1].sum=tr[x<<1].len-tr[x<<1].sum;
            }
            else if(tr[x<<1].f1==1){
                tr[x<<1].sum=tr[x<<1].len;
                tr[x<<1].f1=2;
                tr[x<<1].f2=0;
            }
            else if(tr[x<<1].f1==2){
                tr[x<<1].sum=0;
                tr[x<<1].f1=1;
                tr[x<<1].f2=0;
            }
            else tr[x<<1].f2=1,tr[x<<1].sum=tr[x<<1].len-tr[x<<1].sum;
            if(tr[x<<1|1].f2){
                tr[x<<1|1].f2=0;
                tr[x<<1|1].sum=tr[x<<1|1].len-tr[x<<1|1].sum;
            }
            else if(tr[x<<1|1].f1==1){
                tr[x<<1|1].sum=tr[x<<1|1].len;
                tr[x<<1|1].f1=2;
                tr[x<<1|1].f2=0;
            }
            else if(tr[x<<1|1].f1==2){
                tr[x<<1|1].sum=0;
                tr[x<<1|1].f1=1;
                tr[x<<1|1].f2=0;
            }
            else tr[x<<1|1].f2=1,tr[x<<1|1].sum=tr[x<<1|1].len-tr[x<<1|1].sum;
        }    
    //    printf("down*** f1=%lld f2=%lld lson.f2=%lld rson.f2=%lld  l=%lld r=%lld tr[x].sum=%lld lson l=%lld r=%lld sum=%lld rson l=%lld r=%lld sum=%lld
    ",tr[x].f1,tr[x].f2,tr[x<<1].f2,tr[x<<1|1].f2,tr[x].l,tr[x].r,tr[x].sum,tr[x<<1].l,tr[x<<1].r,tr[x<<1].sum,tr[x<<1|1].l,tr[x<<1|1].r,tr[x<<1|1].sum);
    //    printf("l=%lld r=%lld lson.f1=%lld f2=%lld sum=%lld l=%lld r=%lld rson.f1=%lld f2=%lld sum=%lld
    ",tr[x<<1].l,tr[x<<1].r,tr[x<<1].f1,tr[x<<1].f2,tr[x<<1].sum,tr[x<<1|1].l,tr[x<<1|1].r,tr[x<<1|1].f1,tr[x<<1|1].f2,tr[x<<1|1].sum);
        tr[x].f1=0;
        tr[x].f2=0;
    
    }
    void seg_add(ll x,ll l,ll r,ll val){
    //    printf("l=%lld r=%lld tr[x].l=%lld tr[x].r=%lld
    ",l,r,tr[x].l,tr[x].r);
        
        if(tr[x].l>=l&&tr[x].r<=r){
            if(val==3){//异或
                if(tr[x].f2){
                    tr[x].f2=0;
                    tr[x].sum=tr[x].len-tr[x].sum;
                }
                else if(tr[x].f1==1){
                    tr[x].sum=tr[x].len;
                    tr[x].f1=2;
                    tr[x].f2=0;
                }
                else if(tr[x].f1==2){
                    tr[x].sum=0;
                    tr[x].f1=1;
                    tr[x].f2=0;
                }
                else tr[x].f2=1,tr[x].sum=tr[x].len-tr[x].sum;
            }
            else if(val==1){//区间赋值1
                tr[x].sum=0;
                tr[x].f1=1;
                tr[x].f2=0;
            }
            else if(val==2){
                tr[x].sum=tr[x].len;
                tr[x].f1=2;
                tr[x].f2=0;
            }
    //        printf("havefindit l=%lld r=%lld val=%lld val=%lld
    ",tr[x].l,tr[x].r,tr[x].f1,val);
            return ;
        }
        if(tr[x].f1||tr[x].f2) down(x);
        ll mid=(tr[x].l+tr[x].r)>>1;
        if(mid>=l)seg_add(x<<1,l,r,val);
        if(mid<r) seg_add(x<<1|1,l,r,val);
        up(x);
    }
    void query(ll x){
        if(tr[x].l==tr[x].r){
            ans=lsh[tr[x].l];
            return ;
        }
    //    printf("query l=%lld r=%lld f1=%lld f2=%lld
    ",tr[x].l,tr[x].r,tr[x].f1,tr[x].f2);
        if(tr[x].f1||tr[x].f2) down(x);
        if(tr[x<<1].sum) query(x<<1);
        else query(x<<1|1);
        up(x);
    }
    void check(ll x){
    //    printf("l=%lld r%lld f1=%lld f2=%lld sum=%lld
    ",tr[x].l,tr[x].r,tr[x].f1,tr[x].f2,tr[x].sum);
        if(tr[x].l==tr[x].r) return ;
        check(x<<1);
        check(x<<1|1);
    }
    int main(){
        scanf("%lld",&n);
        lsh[++lsh[0]]=1;
        for(ll i=1;i<=n;i++){
            scanf("%lld%lld%lld",&opt[i],&l[i],&r[i]);
            if(l[i]!=1)
                lsh[++lsh[0]]=l[i]-1;
            lsh[++lsh[0]]=l[i];
            lsh[++lsh[0]]=r[i];
            lsh[++lsh[0]]=r[i]+1;
        }
        sort(lsh+1,lsh+lsh[0]+1);
        len=unique(lsh+1,lsh+lsh[0]+1)-lsh-1;
    //    for(ll i=1;i<=lsh[0];i++){
    //        printf("lsh[i]=%lld len=%lld
    ",lsh[i],len);
    //    }
        for(ll i=1;i<=n;i++){
            l[i]=lower_bound(lsh+1,lsh+len+1,l[i])-lsh;
            r[i]=lower_bound(lsh+1,lsh+len+1,r[i])-lsh;
    //        printf("l=%lld r=%lld
    ",l[i],r[i]);
        }
        built(1,1,len);
        for(ll i=1;i<=n;i++){
            seg_add(1,l[i],r[i],opt[i]);    
            query(1);
    //        check(1);
            printf("%lld
    ",ans);
        }
    }
    View Code

    幸运字符

    题意

    一个由4,7组成字符串,动态最长不下降子序列

    区间反转

    随便记录4,7,47即可,因为包含翻转所以还要记录74

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define A 10010010
    struct node{
        ll l,r,_4,_7,_74,_47,f;
    }tr[A];
    char ch[A],ch2[10];
    ll n,m;
    void up(ll x){
        tr[x]._4=tr[x<<1]._4+tr[x<<1|1]._4;
        tr[x]._7=tr[x<<1]._7+tr[x<<1|1]._7;
        tr[x]._47=max((tr[x<<1]._4+tr[x<<1|1]._7),max(tr[x<<1]._4+tr[x<<1|1]._47,tr[x<<1]._47+tr[x<<1|1]._7));
        tr[x]._74=max((tr[x<<1]._7+tr[x<<1|1]._4),max(tr[x<<1]._74+tr[x<<1|1]._4,tr[x<<1]._7+tr[x<<1|1]._74));
    //    printf("tr[%lld].l=%lld r=%lld _4=%lld _7=%lld _47=%lld _74=%lld tr[ls].l=%lld r=%lld _4=%lld _7=%lld _47=%lld _74=%lld tr[rs].l=%lld r=%lld _4=%lld _7=%lld _47=%lld _74=%lld
    ",x,tr[x].l,tr[x].r,tr[x]._4,tr[x]._7,tr[x]._47,tr[x]._74,tr[x<<1].l,tr[x<<1].r,tr[x<<1]._4,tr[x<<1]._7,tr[x<<1]._47,tr[x<<1]._74,tr[x<<1|1].l,tr[x<<1|1].r,tr[x<<1|1]._4,tr[x<<1|1]._7,tr[x<<1|1]._47,tr[x<<1|1]._74);
    }
    void down(ll x){
        swap(tr[x<<1]._4,tr[x<<1]._7);
        swap(tr[x<<1]._47,tr[x<<1]._74);
        swap(tr[x<<1|1]._4,tr[x<<1|1]._7);
        swap(tr[x<<1|1]._47,tr[x<<1|1]._74);
        tr[x<<1].f^=1,tr[x<<1|1].f^=1;
        tr[x].f=0;
    }
    void built(ll x,ll l,ll r){
        tr[x].l=l,tr[x].r=r;
        if(l==r){
            if(ch[l]=='4')    tr[x]._4=1;
            else tr[x]._7=1;
            return ;
        }
        ll mid=(l+r)>>1;
        built(x<<1,l,mid);
        built(x<<1|1,mid+1,r);
        up(x);
    }
    void change(ll x,ll l,ll r){
        if(tr[x].l>=l&&tr[x].r<=r){
            swap(tr[x]._4,tr[x]._7);
            swap(tr[x]._47,tr[x]._74);    
            tr[x].f^=1;
            return ;
        }
        if(tr[x].f) down(x);
        ll mid=(tr[x].l+tr[x].r)>>1;
        if(mid>=l)change(x<<1,l,r);
        if(mid<r) change(x<<1|1,l,r);
        up(x);
    }
    void query(ll x){
        printf("tr[x].l=%lld r=%lld _4=%lld _7=%lld _47=%lld _74=%lld
    ",tr[x].l,tr[x].r,tr[x]._4,tr[x]._7,tr[x]._47,tr[x]._74);
        if(tr[x].l==tr[x].r) return ;
        query(x<<1);
        query(x<<1|1);
    }
    int main(){
    //    freopen("da.in","r",stdin);
    //    freopen("ans.bf","w",stdout);
        scanf("%lld%lld",&n,&m);
        scanf("%s",ch+1);
        built(1,1,n);
    //    query(1);
        for(ll i=1;i<=m;i++){
            scanf("%s",ch2+1);
    //        printf("i=%lld
    ",i);
            if(ch2[1]=='c'){
                ll maxx=max(max(tr[1]._4,tr[1]._7),tr[1]._47);
                printf("%lld
    ",maxx);
            }
            else {
                ll l,r;
                scanf("%lld%lld",&l,&r);
                change(1,l,r);
            }
    //        query(1);
        }
    }
    View Code

    线段树维护hash

    一般用于必须满足某个顺序时可以用

    代码

    #include<bits/stdc++.h>
    #define ll long long
    #define A 1010100
    #define rill 233
    using namespace std;
    struct node{
        ll l,r,jz;
        unsigned ll val;
        void init(){
            jz=0;val=0;
        }
    }tr[A];
    unsigned ll h[A],p[A];
    void built(ll x,ll l,ll r){
        tr[x].l=l,tr[x].r=r;
        tr[x].init();
        if(l==r){
            tr[x].val=0;
            return ;
        }
        ll mid=(l+r)>>1;
        built(x<<1,l,mid);
        built(x<<1|1,mid+1,r);
    }
    void down(ll x){//
        tr[x<<1].jz+=tr[x].jz;
        tr[x<<1|1].jz+=tr[x].jz;
        tr[x<<1].val*=p[tr[x].jz];
        tr[x<<1|1].val*=p[tr[x].jz];
        tr[x<<1].val+=tr[x].val;
        tr[x<<1|1].val+=tr[x].val;
        tr[x].jz=0;tr[x].val=0;
    }
    void seg_add(ll x,ll l,ll r,ll d){
        if(tr[x].l>=l&&tr[x].r<=r){//
            tr[x].val=tr[x].val*233+d;tr[x].jz++;return ;
        }
        if(tr[x].jz) down(x);
        ll mid=(tr[x].l+tr[x].r)>>1;
        if(mid>=l)seg_add(x<<1,l,r,d);
        if(mid<r) seg_add(x<<1|1,l,r,d);
    }
    ll n,k,t;
    ll ans=0;
    void find(ll x){
        if(tr[x].l==tr[x].r){
            if(tr[x].val==h[k])
                ans++;
            return ;
        }
        if(tr[x].jz) down(x);
        find(x<<1);find(x<<1|1);
    }
    void print(ll x){
        printf("l=%lld r=%lld jz=%lld val=",tr[x].l,tr[x].r,tr[x].jz); cout<<tr[x].val<<endl;
        if(tr[x].l==tr[x].r) return ;
        print(x<<1);print(x<<1|1);
    }
    int main(){
        scanf("%lld%lld%lld",&n,&k,&t);
        p[0]=1;
        for(ll i=1;i<=k;i++)
            h[i]=h[i-1]*233+i,p[i]=p[i-1]*233;
        built(1,1,n);
        while(t--){
            ll l,r,x;
            scanf("%lld%lld%lld",&l,&r,&x);
            seg_add(1,l,r,x);
    //        print(1);
        }
        find(1);
        printf("%lld
    ",ans);
    }
    View Code
  • 相关阅读:
    【LeetCode】328. 奇偶链表
    【LeetCode】24. 两两交换链表中的节点
    【LeetCode】83. 删除排序链表中的重复元素
    【LeetCode】141. 环形链表
    【LeetCode】02.07. 链表相交
    【LeetCode】876. 链表的中间结点
    【LeetCode】2. 两数相加
    【LeetCode】02.01. 移除重复节点
    【LeetCode】21. 合并两个有序链表
    【LeetCode】剑指 Offer 06. 从尾到头打印链表
  • 原文地址:https://www.cnblogs.com/znsbc-13/p/11677838.html
Copyright © 2011-2022 走看看