码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 5919 Sequence II(主席树+区间不同数个数+区间第k小)

时间:2017-10-15 22:28:14      阅读:260      评论:0      收藏:0      [点我收藏+]

标签:code   turn   open   ase   否则   ems   mes   eof   ceil   

http://acm.split.hdu.edu.cn/showproblem.php?pid=5919

题意:
给出一串序列,每次给出区间,求出该区间内不同数的个数k和第一个数出现的位置(将这些位置组成一个新的序列),输出这里面的第ceil(k/2)个数。

 

思路:

因为每个区间只需要统计第一个数出现的位置,那么从右往左来建树,如果该数没有出现,那么就将该位置+1,否则要将上一次出现的位置-1后再在该位置+1。

统计不同数的个数很简单,就是线段树查询。

查询出第k小的数也很简单,因为我们是从后往前建树的,那么t[l]这棵树里面的元素就是从l开始的数组,直接线段树查询第k个数即可。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<stack>
  7 #include<queue>
  8 #include<cmath>
  9 #include<map>
 10 #include<set>
 11 using namespace std;
 12 typedef long long ll;
 13 typedef pair<int,int> pll;
 14 const int INF = 0x3f3f3f3f;
 15 const int maxn = 2*1e5+5;
 16 
 17 int tot,n,m;
 18 int a[maxn],pre[maxn],rot[maxn];
 19 
 20 struct node
 21 {
 22     int l,r,num;
 23 }t[maxn*50];
 24 
 25 int build(int l, int r)
 26 {
 27     int root=++tot;
 28     t[root].num=0;
 29     if(l==r)  return root;
 30     int mid=(l+r)>>1;
 31     t[root].l=build(l,mid);
 32     t[root].r=build(mid+1,r);
 33     return root;
 34 }
 35 
 36 int update(int root, int pos, int d)
 37 {
 38     int now = ++tot;
 39     int tmp = now;
 40     t[tot].num = t[root].num + d;
 41     int l = 1, r = n;
 42     while(l<r)
 43     {
 44         int mid = (l+r)>>1;
 45         if(pos<=mid)
 46         {
 47             t[now].l = ++tot;
 48             t[now].r = t[root].r;
 49             root = t[root].l;
 50             now = tot;
 51             r = mid;
 52         }
 53         else
 54         {
 55             t[now].l = t[root].l;
 56             t[now].r = ++tot;
 57             root = t[root].r;
 58             now = tot;
 59             l = mid + 1;
 60         }
 61         t[now].num = t[root].num + d;
 62     }
 63     return tmp;
 64 }
 65 
 66 int query(int ql ,int qr, int l, int r, int root)
 67 {
 68     if(ql<=l && qr>=r)  return t[root].num;
 69     int mid = (l+r)>>1;
 70     int ans = 0;
 71     if(ql<=mid)  ans+=query(ql,qr,l,mid,t[root].l);
 72     if(qr>mid)   ans+=query(ql,qr,mid+1,r,t[root].r);
 73     return ans;
 74 }
 75 
 76 
 77 int calc(int l,int r,int k,int root)
 78 {
 79     if(l==r)  return l;
 80     int mid = (l+r)>>1;
 81     if(t[t[root].l].num>=k)  return calc(l,mid,k,t[root].l);
 82     else return calc(mid+1,r,k-t[t[root].l].num,t[root].r);
 83 }
 84 
 85 int main()
 86 {
 87     //freopen("in.txt","r",stdin);
 88     int T;
 89     int kase = 0;
 90     scanf("%d",&T);
 91     while(T--)
 92     {
 93         tot=0;
 94         int bef=0;
 95         memset(pre,-1,sizeof(pre));
 96         scanf("%d%d",&n,&m);
 97         for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
 98         rot[n+1] = build(1,n);
 99         for(int i=n;i>0;i--)
100         {
101             if(pre[a[i]] == -1)  rot[i] = update(rot[i+1],i,1);
102             else
103             {
104                 int tmp = update(rot[i+1],pre[a[i]],-1);
105                 rot[i] = update(tmp,i,1);
106             }
107             pre[a[i]] = i ;
108         }
109         printf("Case #%d:",++kase);
110         while(m--)
111         {
112             int l,r;
113             scanf("%d%d",&l,&r);
114             int ll = (l + bef)%n + 1;
115             int rr = (r + bef)%n + 1;
116             l = min(ll, rr);
117             r = max(ll, rr);
118             int k = query(l,r,1,n,rot[l]);
119             k = ceil(k/2.0);
120             int ans = calc(1,n,k,rot[l]);
121             bef = ans;
122             printf(" %d",ans);
123         }
124         puts("");
125     }
126     return 0;
127 }

 

HDU 5919 Sequence II(主席树+区间不同数个数+区间第k小)

标签:code   turn   open   ase   否则   ems   mes   eof   ceil   

原文地址:http://www.cnblogs.com/zyb993963526/p/7674325.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!