zoukankan      html  css  js  c++  java
  • HDU HDOJ5412(树套树or整体二分

    题目:要求支持带修改维护区间第k大的值。所谓的动态区间第k大。

    思路:题解说的是树状数组套treap,然而没想通树状数组怎么维护。。。线段树的话就是把所有的值离散化一下,离线建个关于值的线段树,每个节点是一个treap,treap里的值用位置做关键字,然后做区间查询,复杂度是O(nlogn*logn)。基本也是经典的树套树做法。。。。然后赛后写了两遍都没过。。。。。今天心血来潮再挑战一下,结果从8点调到晚上1点。其间各种爆内存各种re各种t。。。。。随机数据对拍了好久没拍出问题来。。。。然后一直t,,后来突然想到改交vc,结果wa了。。。。然后搞了个数据,结果本地直接re。。简直凌乱了。。。然后随便试试把数组开大。。。结果就过了。。我草。。。明明g++开4e6都爆内存,vc开5e6居然还有富余。。。。然后再开个栈外挂,速度直逼标程。。。。

    结论:这题有毒。。。。基本都是整体二分过的。。。有时间学习一下。。免得这么但疼。。。

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    */
    #pragma comment(linker, "/STACK:102400000,102400000")
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #include <cmath>
    using namespace std;
    #define IOS std::ios::sync_with_stdio(false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps 0.00000001
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    typedef long long ll;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    const int maxNode=5e6+300;
    struct treapNode{
        treapNode *ch[2];
        int right,val;
        int sz;
        treapNode():sz(0){}
        int cmp(int x) const {
            if(x==val) return -1;
            return x>val;
        }
        void maintain(){
            sz=ch[0]->sz+ch[1]->sz+1;
        }
    }pool[maxNode];
    int ph=0;
    treapNode *null=new treapNode();
    treapNode *newtreapNode(int v){
        treapNode *n=&pool[ph++];
        n->val=v;
        n->right=rand();
        n->ch[0]=n->ch[1]=null;
        return n;
    }
    void rotate(treapNode *&o,int d){
        treapNode *k=o->ch[d^1];
        o->ch[d^1]=k->ch[d];
        k->ch[d]=o;
        o->maintain();
        k->maintain();
        o=k;
    }
    void insert(treapNode *&o,int x){
        if(o==null) o=newtreapNode(x);
        else{
            int d=o->val<x;
            insert(o->ch[d],x);
            if(o->ch[d]->right>o->right) rotate(o,d^1);
        }
        o->maintain();
    }
    void remove(treapNode *&o,int x){
        int d=o->cmp(x);
        if(d==-1){
            if(o->ch[0]==null) o=o->ch[1];
            else if(o->ch[1]==null) o=o->ch[0];
            else{
                int d2=o->ch[0]->right>o->ch[1]->right;
                rotate(o,d2);
                remove(o->ch[d2],x);
            }
        }else remove(o->ch[d],x);
        if(o!=null) o->maintain();
    }
    int findless(treapNode *o,int x){
        int r=0;
        while(o!=null){
            if(o->val>x){
                o=o->ch[0];
            }
            else{
                r+=o->ch[0]->sz+1;
                o=o->ch[1];
            }
        }
        return r;
    }
    int culbetween(treapNode *o,int l,int r){
        return findless(o,r)-findless(o,l-1);
    }
    int ah;
    const int maxn=1e6+3000;
    struct QU{
        int t,a,b,c;
    }qu[maxn];
    struct segNode{
        int l,r;
        treapNode *root;
        segNode *ch[2];
    }segpool[maxNode];
    int segh=0;
    segNode *newsegNode(){
        segNode *n=&segpool[segh++];
        n->root=null;
        return n;
    }
    void buildSeg(segNode *n,int l,int r){
        n->l=l,n->r=r;
        if(r-l<=1) return;
        n->ch[0]=newsegNode();
        n->ch[1]=newsegNode();
        buildSeg(n->ch[0],l,(l+r)/2);
        buildSeg(n->ch[1],(r+l)/2,r);
    }
    void segInsert(segNode *n,int x,int p){
        int r=n->r,l=n->l;
        int mid=(r+l)/2;
        treapNode *&tn=n->root;
        insert(tn,p);
        if(r-l<=1) return;
        if(x>=mid)
            segInsert(n->ch[1],x,p);
        else
            segInsert(n->ch[0],x,p);
    }
    void segRemove(segNode *n,int x,int p){
        int r=n->r,l=n->l;
        int mid=(r+l)/2;
        treapNode *&tn=n->root;
        remove(tn,p);
        if(r-l<=1) return;
        if(x>=mid)
            segRemove(n->ch[1],x,p);
        else
            segRemove(n->ch[0],x,p);
    }
    int segQuery(segNode *n,int a,int b,int k){
        treapNode *tn=n->root;
        segNode *chl=n->ch[0],*chr=n->ch[1];
        int l=n->l,r=n->r;
        if(r-l<=1) return l;
        int q1=culbetween(chl->root,a,b);
        if(q1>=k) return segQuery(chl,a,b,k);
        else return segQuery(chr,a,b,k-q1);
    }
    int N;
    int deca[maxn];
    int idx(int x){
        return lower_bound(deca,deca+ah,x)-deca;
    }
    segNode *segRoot;
    void clear(){
        ph=0;
        segh=0;
        segRoot=newsegNode();
    }
    int a[maxn];
    
    template <class T>
    inline bool scan_d(T &ret) {
        char c;
        int sgn;
        if(c=getchar(),c==EOF) return 0; //EOF
        while(c!='-'&&(c<'0'||c>'9')) c=getchar();
        sgn=(c=='-')?-1:1;
        ret=(c=='-')?0:(c-'0');
        while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
        ret*=sgn;
        return 1;
    }
    inline void out(int x) {
        if(x>9) out(x/10);
        putchar(x%10+'0');
    }
    
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        freopen("/home/slyfc/CppFiles/out","w",stdout);
        while(cin>>N){
            clear();
            for(int i=1;i<=N;i++){ 
                scan_d(a[i]);
                deca[i-1]=a[i];
            }
            int Q;
            scan_d(Q);
            int an=N;
            for(int i=1;i<=Q;i++){
                int t;
                scan_d(t);
                if(t==1){
                    int l,v;
                    scan_d(l);scan_d(v);
                    qu[i].a=l,qu[i].b=v;
                    deca[an++]=v;
                }
                else{
                    int l,r,k;
                    scan_d(l);scan_d(r);scan_d(k);
                    qu[i].a=l,qu[i].b=r,qu[i].c=k;
                }
                qu[i].t=t;
            }
            sort(deca,deca+an);
            ah=unique(deca,deca+an)-deca;
            buildSeg(segRoot,0,ah);
            for(int i=1;i<=N;i++)
                segInsert(segRoot,idx(a[i]),i);
            for(int i=1;i<=Q;i++){
                if(qu[i].t==1){
                    int l=qu[i].a,v=qu[i].b;
                    segRemove(segRoot,idx(a[l]),l);
                    a[l]=v;
                    segInsert(segRoot,idx(v),l);
                }else{
                    int l=qu[i].a,r=qu[i].b,k=qu[i].c;
                    printf("%d
    ",deca[segQuery(segRoot,l,r,k)]);
                }
            }
        }
        return 0;
    }
    View Code

     整体二分解法:

    (弱渣如我看了几个小时才看懂= =).总的来说,整体二分就是二分结果,也就是说把最后答案在一个区间内的询问一块处理.但是看完这个思路之后我想了很久,感觉操作顺序和值之间有着无法逾越的鸿沟.............然后下午开始看代码......在这里详细叙述一下我的理解:

    首先肯定是离散话,然后才能按值二分答案,这个过程中,值和操作是一并处理的.比如现在做到了l,r这个值的区间,此时所有的询问的答案都在这个区间里,更新操作的值也在这个范围里,此时,在当前区间里用树状数组统计区间数目,这个算法能够加速的一个主要原理是它同时处理值小于mid的所有询问,这样就兼顾了二分的值和询问的数目.把修改操作改成两个操作,增加删除,可以发现是没有影响的,对于当前统计,只有小于mid的值的更新才对结果有影响,把这些值按顺序进行处理,就可以计算出到达某个询问时小于mid的数有多少(区间用树状数组统计).

    这个算法不论是实现还是速度上都相当有优势.

    /*
    * @author:  Cwind
    */
    #include <bits/stdc++.h>
    
    using namespace std;
    #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
    #define pb push_back
    #define PB pop_back
    #define bk back()
    #define fs first
    #define se second
    #define sq(x) (x)*(x)
    #define eps (1e-10)
    #define INF (1000000300)
    #define clr(x) memset((x),0,sizeof (x))
    #define cp(a,b) memcpy((a),(b),sizeof (b))
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,string> P;
    
    const int maxn=3e5+300;
    int nq,nv;
    int a[maxn];
    int dval[maxn];
    int ans[maxn];
    struct Node{
        int op,l,r,k;
        int id;
        Node(int op,int l,int r,int k,int id):op(op),l(l),r(r),k(k),id(id){}
        Node(){}
    }q[maxn],q1[maxn],q2[maxn];
    struct BIT{
        int a[maxn];
        void add(int p,int v){
            while(p<maxn) a[p]+=v,p+=p&-p;
        }
        int sum(int p){
            int ans=0;
            while(p) ans+=a[p],p-=p&-p;
            return ans;
        }
        void clear(){clr(a);}
    }B;
    void solve(int h,int t,int l,int r){
        int nq1=0,nq2=0;
        if(r-l==1){
            for(int i=h;i<t;i++)
                if(q[i].op)
                    ans[q[i].op]=dval[l];
            return;
        }
        int mid=(r+l)>>1;
        for(int i=h;i<t;i++){
            if(q[i].op){
                int cnt=B.sum(q[i].r)-B.sum(q[i].l-1);
                if(cnt>=q[i].k) q1[nq1++]=q[i];
                else q[i].k-=cnt,q2[nq2++]=q[i];
            }else{
                if(q[i].r<dval[mid]){
                    B.add(q[i].l,q[i].k);
                    q1[nq1++]=q[i];
                }else q2[nq2++]=q[i];
            }
        }
        for(int i=0;i<nq1;i++) 
            if(!q1[i].op) B.add(q1[i].l,-q1[i].k);
        memcpy(q+h,q1,sizeof(Node)*nq1);
        memcpy(q+h+nq1,q2,sizeof(Node)*nq2);
        solve(h,h+nq1,l,mid);
        solve(h+nq1,t,mid,r);
    }
    int N,Q;
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        //freopen("/home/slyfc/CppFiles/out","w",stdout);
        while(scanf("%d",&N)==1){
            B.clear();
            memset(ans,-1,sizeof ans);
            nv=nq=0;
            for(int i=1;i<=N;i++){
                int x;
                scanf("%d",&x);
                a[i]=x;
                q[nq++]=Node(0,i,x,1,i);
                dval[nv++]=x;
            }
            scanf("%d",&Q);
            for(int i=1;i<=Q;i++){
                int x;
                scanf("%d",&x);
                if(x==1){
                    int l,v;
                    scanf("%d%d",&l,&v);
                    q[nq++]=Node(0,l,v,1,i+N);
                    q[nq++]=Node(0,l,a[l],-1,i+N);
                    dval[nv++]=v,a[l]=v;
                }else{
                    int l,r,k;
                    scanf("%d%d%d",&l,&r,&k);
                    q[nq++]=Node(i,l,r,k,i+N);
                }
            }
            sort(dval,dval+nv);
            nv=unique(dval,dval+nv)-dval;
            solve(0,nq,0,nv);
            for(int i=1;i<=Q;i++)
                if(ans[i]!=-1) printf("%d
    ",ans[i]);
        }
        return 0;    
    }
    View Code

     动态区间第k大这个问题比较经典的做法还有树状数组套主席树,但是容易mle;还有一种块状链表的做法,但是复杂度太高了,这题肯定过不了.

  • 相关阅读:
    第6章 静态路由和动态路由(2)_路由汇总和默认路由
    第6章 静态路由和动态路由(1)_静态路由
    第5章 IP地址和子网划分(4)_超网合并网段
    第5章 IP地址和子网划分(3)_子网划分
    第5章 IP地址和子网划分(2)_IP地址分类和NAT技术
    第5章 IP地址和子网划分(1)_IP格式和子网掩码
    第4章 数据链路层(5)_高速以太网
    第4章 数据链路层(4)_扩展以太网
    第4章 数据链路层(3)_广播信道的数据链路
    第4章 数据链路层(2)_点到点信道的数据链路
  • 原文地址:https://www.cnblogs.com/Cw-trip/p/4944071.html
Copyright © 2011-2022 走看看