BZOJ 2223: [Coci 2009]PATULJCI 主席树

心已赠人 2021-11-17 16:24 328阅读 0赞

题目描述:动态求出现次数大于等于区间一半长度的数字.
题解: 对序列维护一个主席树即可.

  1. #include<bits/stdc++.h>
  2. #define maxn 300001
  3. #define mid ((l+r)>>1)
  4. using namespace std;
  5. inline void setIO(string s)
  6. {
  7. string in=s+".in";
  8. freopen(in.c_str(),"r",stdin);
  9. }
  10. int cnt, cc=0;
  11. int ls[maxn*20],rs[maxn*20],sumv[maxn*20],root[maxn];
  12. void build(int l,int r,int &o)
  13. {
  14. o=++cnt;
  15. if(l==r) return;
  16. if(mid>=l) build(l,mid,ls[o]);
  17. if(r>mid) build(mid+1,r,rs[o]);
  18. }
  19. int update(int l,int r,int k,int x)
  20. {
  21. int oo=++cnt;
  22. sumv[oo]=sumv[x]+1;
  23. ls[oo]=ls[x], rs[oo]=rs[x];
  24. if(l==r) return oo;
  25. if(k<=mid) ls[oo]=update(l,mid,k,ls[x]);
  26. else rs[oo]=update(mid+1,r,k, rs[x]);
  27. return oo;
  28. }
  29. int query(int u,int v,int l,int r)
  30. {
  31. if(l==r)
  32. {
  33. if(sumv[v]-sumv[u] > cc) return l;
  34. return -1;
  35. }
  36. int tmp=sumv[ls[v]]-sumv[ls[u]];
  37. if(tmp > cc) return query(ls[u], ls[v], l, mid);
  38. else return query(rs[u], rs[v], mid + 1, r);
  39. }
  40. int main()
  41. {
  42. // setIO("input");
  43. int n,m,i,a,Q,l,r;
  44. scanf("%d%d",&n,&m);
  45. build(1,m,root[0]);
  46. for(i=1;i<=n;++i)
  47. {
  48. scanf("%d",&a);
  49. root[i]=update(1,m,a,root[i-1]);
  50. }
  51. scanf("%d",&Q);
  52. while(Q--)
  53. {
  54. scanf("%d%d",&l,&r);
  55. cc=(r-l+1)>>1;
  56. a = query(root[l-1], root[r], 1, m);
  57. if(a==-1) printf("no\n");
  58. else printf("yes %d\n", a);
  59. }
  60. return 0;
  61. }

  

转载于:https://www.cnblogs.com/guangheli/p/11066429.html

发表评论

表情:
评论列表 (有 0 条评论,328人围观)

还没有评论,来说两句吧...

相关阅读

    相关 【模板】主席

    1.静态区间第k小 题解思路 对于每个位置维护一个线段树,显然每个线段树维护的信息可以加减 所以通过类似前缀和的思想求区间第k小 代码 incl