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 }