http://acm.hdu.edu.cn/showproblem.php?pid=5919
题意: 一个数组A。。。有Q次询问,[L,R](强制在线)。。。询问区间不同数按贡献排序后组成的新数组中的n/2项是什么,贡献是指在这个区间里面最左出现的位置。
思路:主席树套路题。。因为强制在线,所以使用主席树。。方法和主席树求区间不同数的方法是一样的,只需要扫一遍,PS。因为这里要用到最左出现位置,所以从右往左扫。这样我们得到了n个版本的线段树,每个都可以用来查询区间不同数了(和离线版本的BIT思路一样)。接下来询问第k/2其实就是类似一个静态的线段树找第k大的做法,也很简单了。。。第一次写主席树,很神奇。。
代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <complex>
using namespace std;
const int MAXN = 200010;
const int M = MAXN * 40;
int n,q,tot;
int a[MAXN];
int T[MAXN],lson[M],rson[M],c[M];
int build(int l,int r){
int root = tot++;
c[root] = 0;
if(l != r){
int mid = (l+r)>>1;
lson[root] = build(l,mid);
rson[root] = build(mid+1,r);
}
return root;
}
int update(int root,int pos,int val){
int newroot = tot++, tmp = newroot;
c[newroot] = c[root] + val;
int l = 1, r = n;
while(l < r){
int mid = (l+r)>>1;
if(pos <= mid){
lson[newroot] = tot++;
rson[newroot] = rson[root];
newroot = lson[newroot];
root = lson[root];
r = mid;
}
else{
rson[newroot] = tot++;
lson[newroot] = lson[root];
newroot = rson[newroot];
root = rson[root];
l = mid+1;
}
c[newroot] = c[root] + val;
}
return tmp;
}
int query(int root,int pos){
int ret = 0;
int l = 1, r = n;
while(pos < r){
int mid = (l+r)>>1;
if(pos <= mid){
r = mid;
root = lson[root];
}
else{
ret += c[lson[root]];
root = rson[root];
l = mid+1;
}
}
return ret + c[root];
}
int query2(int root,int k){
int ret = 0;
int l = 1, r = n;
while(l < r){
int mid = (l+r)>>1;
if(k <= c[lson[root]]){
r = mid;
root = lson[root];
}
else{
k-=c[lson[root]];
root = rson[root];
l = mid+1;
}
if(l==r) return l;
}
return r;
}
int mp[MAXN];
int Q[MAXN];
int main(){
Q[0]=0;
int t,cas=1;
scanf("%d",&t);
while(t--){
tot = 0;
scanf("%d%d",&n,&q);
for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
T[n+1] = build(1,n);
memset(mp,0,sizeof(mp));
for(int i = n; i>= 1; i--){
if(mp[a[i]] == 0){
T[i] = update(T[i+1],i,1);
}
else{
int tmp = update(T[i+1],mp[a[i]],-1);
T[i] = update(tmp,i,1);
}
mp[a[i]] = i;
}
for(int i=1;i<=q;i++){
int l,r;
scanf("%d%d",&l,&r);
l=(l+Q[i-1])%n+1;
r=(r+Q[i-1])%n+1;
if(r<l) swap(l,r);
int sum=query(T[l],r);
Q[i]=query2(T[l],(sum+1)/2);
}
printf("Case #%d:",cas++);
for(int i=1;i<=q;i++) printf(" %d",Q[i]);
printf("
");
}
return 0;
}