题意:
有长度为n的序列,强制在线询问
分析:
- 如果可以离线做,那么按照l排个序以后,从右想左逐个添加新的位置,删除前一个位置。
- 但是这个强制在线怎么搞, 那就把以
[l,n] 序列形成的线段树都存下来,然后在对应的线段树上面搞一下,就行了。这个时候用主席树来存就好了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <string>
using namespace std;
typedef long long LL;
typedef vector <int> VI;
typedef pair <int,int> PII;
#define FOR(i,x,y) for(int i = (int)(x);i < (int)(y);++ i)
#define IFOR(i,x,y) for(int i = (int)(x);i > (int)(y);-- i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
const int maxn = 200005;
struct Tree{
int ls, rs, sum;
}tree[maxn*50];
int rt[maxn], tot, sz;
int build(int l,int r) {
int o = tot ++;
tree[o].sum = 0;
if(l == r) return o;
int mid = (l+r)>>1;
tree[o].ls = build(l, mid);
tree[o].rs = build(mid+1, r);
return o;
}
int update(int x, int l, int r, int lt, int v) {
int o = tot ++;
tree[o] = tree[lt];
tree[o].sum += v;
if(l == r) return o;
int mid = (l+r)>>1;
if(x <= mid) tree[o].ls = update(x, l, mid, tree[lt].ls, v);
else tree[o].rs = update(x, mid+1, r, tree[lt].rs, v);
return o;
}
int query(int i, int l, int r, int ll, int rr) {
if(ll == l && rr == r) return tree[i].sum;
int mid = (l+r)>>1;
if(rr <= mid) return query(tree[i].ls, l, mid, ll, rr);
else if(ll > mid) return query(tree[i].rs, mid+1, r, ll, rr);
else return query(tree[i].ls, l, mid, ll, mid)+query(tree[i].rs, mid+1, r, mid+1, rr);
}
int query2(int i, int l, int r, int v) {
if(l == r) return l;
int mid = (l+r)>>1;
if(v <= tree[tree[i].ls].sum) return query2(tree[i].ls, l, mid, v);
else return query2(tree[i].rs, mid+1, r, v-tree[tree[i].ls].sum);
}
int n, m, a[maxn], id[maxn], nt[maxn], ans[maxn];
int main() {
//freopen("test.in", "r", stdin);
int T, tCase = 0; scanf("%d", &T);
while(T--) {
printf("Case #%d:", ++ tCase);
scanf("%d%d", &n, &m);
FOR(i, 1, n+1) scanf("%d", a+i);
sz = n+1;
FOR(i, 1, n+2) id[i] = n+1;
IFOR(i, n, 0) nt[i] = id[a[i]], id[a[i]] = i;
tot = 0;
rt[n+1] = build(1, sz);
IFOR(i, n, 0) {
if(nt[i] == n+1) {rt[i] = update(i, 1, sz, rt[i+1], 1); continue;}
int o = update(nt[i], 1, sz, rt[i+1], -1);
rt[i] = update(i, 1, sz, o, 1);
}
ans[0] = 0;
FOR(i, 1, m+1) {
int l, r;
scanf("%d%d", &l, &r);
l = (l+ans[i-1]%n)%n+1; r = (r+ans[i-1]%n)%n+1;
if(l > r) swap(l, r);
int sum = query(rt[l], 1, sz, 1, r);
//cout << i << "\n" << "sum:" << sum << " l:" << l << " r:" << r << endl;
sum = (sum+1)>>1;
ans[i] = query2(rt[l], 1, sz, sum);
printf(" %d", ans[i]);
}
printf("\n");
}
return 0;
}