zoukankan      html  css  js  c++  java
  • GSS3/1

    这个题集好好,那天我做一下(开个大坑?)

    嘛,题目难的是查询,这里就只讲查询了

    根据题解,我们用线段树维护3个东西

    lx:表示从lx走,所能在给定区间里面的最大值

    rx:参考上面

    mx:表示在给定区间中间截取一段所能取到的最大值

    那么对于题目给定的查询区间(假设其为L,R)

    我们用线段树去遍历这个区间(访问,,,,,比较好点吧)

    如果L---R刚好对应线段树的一个区间,那么直接返回我们的mx就好了(正确性显然)

    相对的,存在不对应区间的情况

    考虑合并答案

    对于我们线段树的每次操作相当于把一段区间一分为二

    那么我们可以借用线段树的操作,维护一个在线段树维护范围内的又在L---R的部分答案

    然后就可以合并

    对于这个部分答案,很好维护

    只要将遍历所有L---R内的线段树局部节点就可以解决

    #include<bits/stdc++.h>
    #define MAXN 400000
    using namespace std;
    
    int n,q,date[MAXN];
    int tp,mb1,mb2;
    struct node{
        int sum;
        int lx,rx,mx;
    }t[MAXN*4];
    
    int up(int now){
        t[now].sum = t[now*2].sum+t[now*2+1].sum;
        t[now].lx = max(t[now*2].lx,t[now*2].sum+t[now*2+1].lx);
        t[now].rx = max(t[now*2+1].rx,t[now*2].rx+t[now*2+1].sum);
        t[now].mx = max(max(t[now*2].mx,t[now*2+1].mx),t[now*2].rx+t[now*2+1].lx);
    }
    
    int build(int ll,int rr,int now){
        if(ll==rr){
            t[now].lx = t[now].rx = t[now].mx = t[now].sum = date[ll];
            return 0;
        }
        int mid = (ll+rr)>>1;
        build(ll,mid,now*2);
        build(mid+1,rr,now*2+1);
        up(now);
    }
    
    int change(int now,int l,int r,int x,int y){//在x上改成y 
        int mid = (l+r)>>1;
        if(r<x||l>x)return 0;
        if(x==l&&x==r){
            t[now].lx = t[now].rx = t[now].mx = t[now].sum = y;
            return 0;
        }
        change(now*2+1,mid+1,r,x,y);
        change(now*2,l,mid,x,y);
        
        up(now);
        
    }
    
    node found(int ml,int mr,int now,int l,int r){
        if(l>=ml&&r<=mr){
            return t[now];        
        }     
        int mid = (l+r)>>1;
        node ans,a,b;
        if(mid<ml)return found(ml,mr,now*2+1,mid+1,r);
        if(mid>=mr)return found(ml,mr,now*2,l,mid); 
        else{
        a = found(ml,mr,now*2,l,mid);
        b = found(ml,mr,now*2+1,mid+1,r);
        ans.sum = a.sum+b.sum;
        ans.lx = max(a.lx,a.sum+b.lx);
        ans.rx = max(a.rx+b.sum,b.rx);
        ans.mx = max(a.rx+b.lx,max(a.mx,b.mx));
        return ans;    
        }
    }
    
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>date[i];
        }
        build(1,n,1);
        cin>>q;
        for(int i=1;i<=q;i++){
            cin>>tp>>mb1>>mb2;
            if(tp==1){
                node p=found(mb1,mb2,1,1,n);
            cout<<p.mx<<endl;
            }
            else{
                change(1,1,n,mb1,mb2);
            }
            
        }
    }
    View Code

    当然,也可以用平衡树解决此问题(嘛,平衡树完全不会做....)

    一般的,假设平衡树已经维护了原区间序列的编号

    只要使L-1作为根节点,R+1作为根右节点,此时因为平衡树同时满足BST性质

    故R的左子树就是L---R区间的编号(一开始搞懵了)

    本质上在平衡树上对原序列的操作是不需要遵守BST性质的

    因为与编号无关,只与编号映射的集合有关

    那么考虑 提取区间后的操作....

    同样的参照线段树做法...维护3个东西lx,rx,mx

    (此时开始乱搞....)

    嘛,直接仿造线段树的插入方式,但维护的不是区间是节点....

    然后考虑旋转怎么维护那3坨东西

    嘛,考虑到变的只有旋转点和旋转点父亲

    直接up一下就好

     -----------------------------------蒟蒻分割线

     不过还好,让我重温线段树....

    嘛....

    splay的代码...

    #include<bits/stdc++.h>
    #define MAXN 100005
    using namespace std;
    
    int n,q,ma,mb,tp;
    int date[MAXN];
    int lx[MAXN],rx[MAXN],mx[MAXN],sum[MAXN];
    struct Splay{
        int num[MAXN],ch[MAXN][2],sz[MAXN],f[MAXN],cnt[MAXN],rt,tot,tag[MAXN];
        int get(int x){
            return (x==ch[f[x]][1]);
        }
        int up(int x){
            sz[x] = cnt[x];
            if(ch[x][0])sz[x] = sz[x]+sz[ch[x][0]];
            if(ch[x][1])sz[x] = sz[x]+sz[ch[x][1]];
            sum[x] = date[x]+sum[ch[x][0]]+sum[ch[x][1]];
            lx[x] = max(lx[ch[x][0]],lx[ch[x][1]]+sum[ch[x][0]]+date[x]);
            rx[x] = max(rx[ch[x][1]],rx[ch[x][0]]+sum[ch[x][1]]+date[x]);
            mx[x] = max(max(mx[ch[x][0]],mx[ch[x][1]]),date[x]+rx[ch[x][0]]+lx[ch[x][1]]);
            return 0;
        }
        int down(int x){
            if(tag[x]){
            tag[x] = 0;
            swap(ch[x][0],ch[x][1]);
            if(ch[x][0])tag[ch[x][0]] = tag[ch[x][0]]^1;
            if(ch[x][1])tag[ch[x][1]] = tag[ch[x][1]]^1;
            }
        }
        int found(int x){
            int now=rt,ans=1;
            while(1){
                if(num[now]<=x){
                    ans =     ans+sz[ch[now][0]];
                    if(num[now]==x){
                    return ans;
                    }
                    ans = ans+cnt[now];
                    now = ch[now][1];
                }
                else{
                    now = ch[now][0];
                }
            }
        }
        int rote(int x){
            int y = f[x],z = f[y],k = get(x),p = get(y);
            down(y),down(x);
            if(y==0)return 0;
            if(z)ch[z][p] = x;
            if(ch[x][k^1])f[ch[x][k^1]] = y;
            ch[y][k] = ch[x][k^1];
            ch[x][k^1] = y;
            f[x] = z;
            f[y] = x;
            up(y);up(x);
            return 0;
        }
        int splay(int x){
            for(int y = f[x];(y = f[x]);rote(x)){
                rote((get(x)==get(y))?y:x);
            }
            rt = x;
            return 0;
        }
        int rank(int x){
            int now=rt,ans=1;
            while(1){
                if(num[now]<=x){
                    ans =     ans+sz[ch[now][0]];
                    if(num[now]==x){
                    splay(now);
                    return ans;
                    }
                    ans = ans+cnt[now];
                    now = ch[now][1];
                }
                else{
                    now = ch[now][0];
                }
            }
        }
        int pre(){//前继 比她小的最大 
            int now = ch[rt][0];
            while(ch[now][1])now = ch[now][1];
            return now;
        }
        int suc(){
            int now = ch[rt][1];
            while(ch[now][0])now = ch[now][0];
            return now;
        }
        int add(int x){
            int now = rt;
            while(1){
                down(now);
                if(num[now]==x){
                    cnt[now]++;
                    splay(now);
                    return 0;
                }
                int to = (num[now]<x);
                if(!ch[now][to]){
                    tot++;
                    ch[now][to] = tot;
                    num[tot] = x;
                    f[tot] = now;
                    cnt[tot] = 1;
                    sz[tot] = 1;
                    splay(tot);
                    return 0;
                }
                else now = ch[now][to];
            }
        }
        int kth(int x){
            int now =rt;
            while(1){
                down(now);
                if(sz[ch[now][0]]<x){
                    x = x-sz[ch[now][0]];
                    if(x<=cnt[now])return num[now];
                    x = x-cnt[now];
                    now = ch[now][1];
                }
                else{
                    now = ch[now][0];
                }
            }
        }
        int del(int x){
            rank(x);
            if(cnt[rt]>=2){
                cnt[rt]--;
                sz[rt]--;
                return 0;
            }
            else{
                if((!ch[rt][0])&&(!ch[rt][1])){
                    rt = 0;
                    return 0;
                }
                if(ch[rt][0]&&(!ch[rt][1])){
                    f[ch[rt][0]] = 0;
                    rt =ch[rt][0];
                    return 0;
                }
                if((!ch[rt][0])&&ch[rt][1]){
                    f[ch[rt][1]] = 0;
                    rt =ch[rt][1];
                    return 0;
                }
                else{
                    splay(pre());
                    ch[rt][1] = ch[ch[rt][1]][1];
                    f[ch[rt][1]] = rt;
                    up(rt);
                    return 0;
                }
            }
        }
        int splay2(int x){
            for(int y = f[x];(y = f[x])!=rt;rote(x)){
                if(f[y]!=rt)rote((get(x)==get(y))?y:x);
            }
            return 0;
        }
        int turn(int x,int g){
            int p=kth(x-1),k=kth(g+1);
            splay(p);
            splay2(k);
            tag[ch[ch[rt][1]][0]] = 1^tag[ch[ch[rt][1]][0]];
        }
        int change(int x,int g){
            int p=kth(x-1),k=kth(x+1);
            splay(p);
            splay2(k);
            date[ch[ch[rt][1]][0]] = g;
            lx[ch[ch[rt][1]][0]] = rx[ch[ch[rt][1]][0]] = max(g,0);
            sum[ch[ch[rt][1]][0]] = mx[ch[ch[rt][1]][0]] = g;    
            up(ch[rt][1]);
            up(rt);
        }
        int found(int x,int g){
            int p=kth(x-1),k=kth(g+1);
            splay(p);
            splay2(k);
            cout<<mx[ch[ch[rt][1]][0]]<<endl;
        }
        int print(int now){
            down(now);
            if(ch[now][0])print(ch[now][0]);
            if(num[now]>1&&num[now]<n+2)cout<<num[now]-1<<" ";
            if(ch[now][1])print(ch[now][1]);
        }
        
    }T;
    
    int main(){
        //freopen("out.txt","r",stdin);
        cin>>n;
        mx[0] = date[1] = date[2] =-1e9;//一定要设置 
        for(int i=2;i<=n+1;i++){
        cin>>date[i];
        //lx[i] = rx[i] = max(date[i],0);
        //sum[i] = mx[i] = date[i];    
        }
        for(int i=1;i<=n+2;i++)T.add(i);
        cin>>q;
        for(int i=1;i<=q;i++){
            cin>>tp>>ma>>mb;
            if(tp==0){
                T.change(ma+1,mb);
            }
            else{
                T.found(ma+1,mb+1);    
            }
        }
    }
    View Code

    抄模板真香(是不是该学分快了..)

  • 相关阅读:
    微信开发-如何自定义页面分享元素
    nginx实现日志按天切割
    JS兼容IE浏览器的方法
    mysql 索引过长1071-max key length is 767 byte
    playframework1.x的eclipse插件开源-playtools
    开放平台-web实现人人网第三方登录
    开放平台-web实现QQ第三方登录
    bash shell执行方式
    pushd和popd
    What do cryptic Github comments mean?
  • 原文地址:https://www.cnblogs.com/shatianming/p/12237036.html
Copyright © 2011-2022 走看看