zoukankan      html  css  js  c++  java
  • middle

    传送门

    主席树大好题……这道题让主席树不仅停留在了区间第k大上,而是让它能执行像线段树一样的操作。

    首先我们先说点套路的事。求中位数有一个二分法,就是每次二分答案,把大于等于当前二分的数设为1,小于的设为-1,之后我们只要看和是否大于0就能判断限制二分的值是大是小。然后虽然区间是不确定的,但是我们要求最大的中位数,只要取中间固定的一段+左区间最大后缀+右区间最大前缀判断即可。

    不过这样的话每次暴力的时候,查询是(O(nlogn))的,再套上查询次数会超时。如何优化一下呢?如果我们用线段树对于每一个二分的值,都维护一下它当前的值和最大前后缀,这样的话我们就只需要(O(log^2n))的复杂度来完成一次查询。但是这样会(MLE)

    然后在每两棵树之间,其实只有(i-1)发生了变化,从1变成了-1.这样的话我们就可以把这些线段树建成主席树,用主席树来实现线段树一样的操作就好了。注意这道题是把以当前这个数的值为根,以位置为值域,注意访问区间不要开小(我就因为这个大数据(MLE)),最开始建树的地方比较重要,我们需要开一个(vector)来把数的值一样,多次出现的数的位置都存起来,然后按照值的大小按顺序修改即可。

    看一下代码。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<vector>
    #include<map>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define fr friend inline
    #define y1 poj
    #define mp make_pair
    #define pr pair<int,int>
    #define fi first
    #define sc second
    #define pb push_back
    #define I puts("Oops")
    
    using namespace std;
    typedef long long ll;
    const int M = 20005;
    const int N = 1000005;
    const int INF = 1000000009;
    const double eps = 1e-7;
    
    int read()
    {
        int ans = 0,op = 1;char ch = getchar();
        while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
        while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
        return ans * op;
    }
    
    struct node
    {
       int ls,rs,v,lv,rv;
    }t[N<<2];
    
    int n,Q,a[M],b[M],root[M],q[6],x,y,z,e,tot,la,L,R,g,idx;
    vector <int> V[M];
    
    void update(int p)
    {
       t[p].v = t[t[p].ls].v + t[t[p].rs].v;
       t[p].lv = max(t[t[p].ls].lv,t[t[p].ls].v + t[t[p].rs].lv);
       t[p].rv = max(t[t[p].rs].rv,t[t[p].rs].v + t[t[p].ls].rv);
    }
    
    void build(int &p,int l,int r)
    {
       if(!p) p = ++idx;
       if(l == r) {t[p].v = t[p].lv = t[p].rv = 1;return;}
       int mid = (l+r) >> 1;
       build(t[p].ls,l,mid),build(t[p].rs,mid+1,r);
       update(p);
    }
    
    void modify(int old,int &p,int l,int r,int val)
    {
       p = ++idx;
       t[p] = t[old];
       if(l == r) {t[p].v = t[p].lv = t[p].rv = -1;return;}
       int mid = (l+r) >> 1;
       if(val <= mid) modify(t[old].ls,t[p].ls,l,mid,val);
       else modify(t[old].rs,t[p].rs,mid+1,r,val);
       update(p);
    }
    
    int query(int p,int l,int r,int kl,int kr)
    {
       //I;
       if(kr < kl) return 0;
       if(l == kl && r == kr) return t[p].v;
       int mid = (l+r) >> 1;
       if(kr <= mid) return query(t[p].ls,l,mid,kl,kr);
       else if(kl > mid) return query(t[p].rs,mid+1,r,kl,kr);
       else return query(t[p].ls,l,mid,kl,mid) + query(t[p].rs,mid+1,r,mid+1,kr);
    }
    
    int ask(int p,int l,int r,int kl,int kr,bool flag)//1 left , 0 right
    {
       //I;
       //printf("#%d %d %d %d
    ",l,r,kl,kr);
       if(l == kl && r == kr) return flag ? t[p].lv : t[p].rv;
       int mid = (l+r) >> 1;
       if(kr <= mid) return ask(t[p].ls,l,mid,kl,kr,flag);
       else if(kl > mid) return ask(t[p].rs,mid+1,r,kl,kr,flag);
       else
       {
          int cur1 = 0,cur2 = 0;
          cur1 = flag ? ask(t[p].ls,l,mid,kl,mid,flag) : ask(t[p].rs,mid+1,r,mid+1,kr,flag);
          if(flag) cur2 = query(t[p].ls,l,mid,kl,mid) + ask(t[p].rs,mid+1,r,mid+1,kr,flag);
          else cur2 = query(t[p].rs,mid+1,r,mid+1,kr) + ask(t[p].ls,l,mid,kl,mid,flag);
          return max(cur1,cur2);
       }
    }
    
    bool judge(int x)
    {
       int cur1 = query(root[x],1,n,q[2]+1,q[3]-1);
       int cur2 = ask(root[x],1,n,q[1],q[2],0);
       int cur3 = ask(root[x],1,n,q[3],q[4],1);
       return cur1 + cur2 + cur3 >= 0;
    }
    
    int main()
    {
       n = read(),build(root[0],1,n);
       rep(i,1,n) a[i] = b[i] = read();
       sort(b+1,b+1+n),tot = unique(b+1,b+1+n) - b - 1;
       rep(i,1,n) a[i] = lower_bound(b+1,b+1+tot,a[i]) - b,V[a[i]].pb(i);
       rep(i,1,tot)
       {
          root[i] = root[i-1];
          rep(j,0,(int)V[i-1].size()-1) modify(root[i],root[i],1,n,V[i-1][j]);
       }
       Q = read();
       rep(i,1,Q)
       {
          rep(j,1,4) q[j] = read(),q[j] = (q[j] + la) % n + 1;
          sort(q+1,q+5),L = 1,R = tot;
          while(L < R)
          {
    	 int mid = (L+R+1) >> 1;
    	 if(judge(mid)) L = mid;
    	 else R = mid - 1;
          }
          la = b[L];
          printf("%d
    ",la);
       }
       return 0;
    }
    
    
  • 相关阅读:
    SAP HANA中创建分析权限(Analytic Privilege)
    SAP HANA 中的决策表(Decision Table)
    SAP HANA procudure 创建用户
    数据挖掘与分析学习链接汇总
    Wpf 自定义窗体
    Winform里实现一个双击ListBox可以切换为TextBox编辑的效果
    一个从没见过的C# ?.语法
    VB.net怎么用Sub Main
    Office2010 帮助查看器遇到意外问题
    WcfService:单服务多契约接口以及用户名密码认证
  • 原文地址:https://www.cnblogs.com/captain1/p/10102867.html
Copyright © 2011-2022 走看看