• bzoj3524 [POI2014]Couriers


    传送门

    分析

    我看到这个题的第一反应使用莫队水过去,于是我考虑建立一棵权值线段树,每一次从里面插入或删除一个数,然后查询,但是复杂度是O(n√nlogn),明显不行。由于这是在一个区间查询数量,所以可以考虑用主席树来维护。建树过程不必说了,查询过程我们是在查询是不是有一个点的值大于k,所以我们每一次如果左子树的总数量大于等于k就查询左子树,右子树大于等于k就查询右子树,如果都不满足就返回0。总复杂度O(nlogn)。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #include<cstdlib>
    #include<queue>
    #include<ctime>
    #include<vector>
    #include<set>
    #include<map>
    #include<stack>
    using namespace std;
    struct node {
          int l,r,sum;
    };
    node d[15000100];
    int rt[510000],a[510000],n,m,cnt;
    inline void build(int le,int ri,int &x,int y,int pl){
          x=++cnt;
          d[x]=d[y];
          d[x].sum++;
          if(le==ri)return;
          int mid=(le+ri)>>1;
          if(mid>=pl)build(le,mid,d[x].l,d[y].l,pl);
            else build(mid+1,ri,d[x].r,d[y].r,pl);
          return;
    }
    inline int q(int le,int ri,int x,int y,int k){
          if(le==ri)return le;
          int mid=(le+ri)>>1,t=d[y].sum-d[x].sum,h=d[d[y].l].sum-d[d[x].l].sum;
          if(h>=k)return q(le,mid,d[x].l,d[y].l,k);
            else if(t-h>=k)return q(mid+1,ri,d[x].r,d[y].r,k);
            else return 0;
    }
    int main(){
          int i,j,k,x,y;
          scanf("%d%d",&n,&m);
          for(i=1;i<=n;i++){
            scanf("%d",&a[i]);
            build(1,n,rt[i],rt[i-1],a[i]);
          }
          for(i=1;i<=m;i++){
              scanf("%d%d",&x,&y);
              printf("%d
    ",q(1,n,rt[x-1],rt[y],(y-x+1)/2+1));
          }
          return 0;
    }
  • 相关阅读:
    Linux makefile教程之概述一[转]
    Valid Parentheses
    Letter Combinations of a Phone Number
    机器学习经典分类算法 —— C4.5算法(附python实现代码)
    3Sum Closest
    3Sum
    Integer to Roman
    寒假文献阅读(四)
    Longest Common Prefix
    Roman to Integer
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/9504299.html
Copyright © 2020-2023  润新知