美文网首页数据结构信息学竞赛题解(IO题解)
BZOJ-3110: [Zjoi2013]K大数查询 题解(树状

BZOJ-3110: [Zjoi2013]K大数查询 题解(树状

作者: AmadeusChan | 来源:发表于2018-10-03 13:09 被阅读10次

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3110

    思路:用树状数组套线段树求解。

    首先,将所有操作离线,然后对要插入的所有数进行离散化,然后每个树状数组节点上建议一棵维护权值的线段树,线段树节点[l,r]维护的即是排名从l到r的数的数目。然后用主席树的方法进行查询第K最值,用处理树状数组区间加的方法(https://www.jianshu.com/p/b93b3a55d21e)处理前缀和。最后,由于每个节点都建立一棵完整的线段树会超时超空间,所以线段树要动态建树,最开始树状数组的索引数组上都是一个空节点,在需要修改的时候才拓展出其他要修改用的线段树节点,这样就将总空间复杂度从O(n^2)降到了O(n log n),时间复杂度也降到了O(n log^2 n),可以通过此题。

    代码:

    #include <cstdio>
    
    #include <algorithm>
    
    #include <cstring>
    
    #include <cstdlib>
    
       
    
    using namespace std;
    
       
    
    #define MAXN 50001
    
    #define lowbit(x)(((~(x))+1)&x)
    
    #define MAXM 20
    
       
    
    int d[MAXN],a[MAXN],b[MAXN],c[MAXN];
    
    int N,M,m=0,R=0;
    
    int r[MAXN];
    
    int MM[MAXN];
    
       
    
    struct saver {
    
        int v,t;
    
    } w[MAXN];
    
       
    
    bool cmp(saver x,saver y){
    
        return x.v>y.v;
    
    }
    
       
    
    struct node {
    
        int l,r,s;
    
        node *left,*right;
    
        node (){
    
            left=right=NULL;
    
        }
    
    };
    
       
    
    node *t0[MAXN],*t1[MAXN];
    
       
    
    void Build(int l,int r,node *t){
    
        t->l=l;
    
        t->r=r;
    
        t->s=0;
    
        if (l==r) return ;
    
        Build(l,(l+r)>>1,t->left=new(node));
    
        Build(((l+r)>>1)+1,r,t->right=new(node));
    
    }
    
       
    
    void Add(int x,int y,node *t){
    
        t->s+=y;
    
        if (t->l==t->r) return ;
    
        int mid=(t->l+t->r)>>1;
    
        if (x<=mid){
    
            if (!t->left){
    
                t->left=new(node);
    
                t->left->l=t->l;
    
                t->left->r=mid;
    
                t->left->s=0;
    
            }
    
            Add(x,y,t->left);
    
        } else {
    
            if (!t->right){
    
                t->right=new(node);
    
                t->right->l=mid+1;
    
                t->right->r=t->r;
    
                t->right->s=0;
    
            }
    
            Add(x,y,t->right);
    
        }
    
    }
    
       
    
    int main(){
    
        scanf("%d%d",&N,&M);
    
        for (int i=0;i++<M;){
    
            scanf("%d%d%d%d",&d[i],&a[i],&b[i],&c[i]);
    
            if (d[i]==1){
    
                w[m].v=c[i];
    
                w[m++].t=i;
    
            }
    
        }
    
        sort(w,w+m,cmp);
    
        r[w[0].t]=1;
    
        MM[1]=w[0].v;
    
        R=1;
    
        for (int i=1;i<m;i++){
    
            if (w[i].v!=w[i-1].v)
    
                MM[++R]=w[i].v;
    
            r[w[i].t]=R;
    
        }
    
        memset(t0,0,sizeof(t0));
    
        memset(t1,0,sizeof(t1));
    
        Build(1,R,t0[0]=new(node));
    
        Build(1,R,t1[0]=new(node));
    
        for (int i=0;i++<N;){
    
            t0[i]=new(node);
    
            t0[i]->l=1;
    
            t0[i]->r=R;
    
            t0[i]->s=0;
    
            t1[i]=new(node);
    
            t1[i]->l=1;
    
            t1[i]->r=R;
    
            t1[i]->s=0;
    
        }
    
        for (int I=0;I++<M;){
    
            if (d[I]==1){
    
                int i=a[I];
    
                while (i<=N){
    
                    Add(r[I],1,t0[i]);
    
                    Add(r[I],a[I],t1[i]);
    
                    i+=lowbit(i);
    
                }
    
                i=b[I]+1;
    
                while (i<=N){
    
                    Add(r[I],-1,t0[i]);
    
                    Add(r[I],-b[I]-1,t1[i]);
    
                    i+=lowbit(i);
    
                }
    
            } else {
    
                node *c1[MAXM],*c2[MAXM],*c3[MAXM],*c4[MAXM];
    
                int m1=0,m2=0;
    
                int i=b[I];
    
                while (i){
    
                    c1[++m1]=t0[i];
    
                    c2[m1]=t1[i];
    
                    i-=lowbit(i);
    
                }
    
                i=a[I]-1;
    
                while (i){
    
                    c3[++m2]=t0[i];
    
                    c4[m2]=t1[i];
    
                    i-=lowbit(i);
    
                }
    
                node *t=t0[0];
    
                while (t->l!=t->r){
    
                    long long sum1=0,sum2=0;
    
                    for (int i=0;i++<m1;){
    
                        if (c1[i]) {
    
                            if (c1[i]->left) sum1+=(b[I]+1)*c1[i]->left->s;
    
                        }
    
                        if (c2[i]) {
    
                            if (c2[i]->left) sum1-=c2[i]->left->s;
    
                        }
    
                    }
    
                    for (int i=0;i++<m2;){
    
                        if (c3[i]) {
    
                            if (c3[i]->left) sum2+=a[I]*c3[i]->left->s;
    
                        }
    
                        if (c4[i]) {
    
                            if (c4[i]->left) sum2-=c4[i]->left->s;
    
                        }
    
                    }
    
                    long long sum=sum1-sum2;
    
                    if (sum>=c[I]) {
    
                        t=t->left;
    
                        for (int i=0;i++<m1;){
    
                            if (c1[i]) c1[i]=c1[i]->left;
    
                            if (c2[i]) c2[i]=c2[i]->left;
    
                        }
    
                        for (int i=0;i++<m2;){
    
                            if (c3[i]) c3[i]=c3[i]->left;
    
                            if (c4[i]) c4[i]=c4[i]->left;
    
                        }
    
                    } else {
    
                        c[I]-=sum;
    
                        t=t->right;
    
                        for (int i=0;i++<m1;){
    
                            if (c1[i]) c1[i]=c1[i]->right;
    
                            if (c2[i]) c2[i]=c2[i]->right;
    
                        }
    
                        for (int i=0;i++<m2;){
    
                            if (c3[i]) c3[i]=c3[i]->right;
    
                            if (c4[i]) c4[i]=c4[i]->right;
    
                        }
    
                    }
    
                }
    
                printf("%d\n",MM[t->l]);
    
            }
    
        }
    
        return 0;
    
    }
    
    

    相关文章

      网友评论

        本文标题:BZOJ-3110: [Zjoi2013]K大数查询 题解(树状

        本文链接:https://www.haomeiwen.com/subject/plvzoftx.html