HDU 5919 Sequence II 主席树
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5919
Sequence II
Memory Limit: 131072/131072 K (Java/Others)
> Note that ki is the number of different integers in this subsequence. You should output p(i)⌈ki2⌉for the i-th query. #### 输入 > In the first line of input, there is an integer T (T≤2) denoting the number of test cases. > > Each test case starts with two integers n (n≤2×105) and m (m≤2×105). There are n integers in the next line, which indicate the integers in the sequence(i.e., a1,a2,⋯,an,0≤ai≤2×105). > > There are two integers li and ri in the following m lines. > > However, Mr. Frog thought that this problem was too young too simple so he became angry. He modified each query to l‘i,r‘i(1≤l‘i≤n,1≤r‘i≤n). As a result, the problem became more exciting. > > We can denote the answers as ans1,ans2,⋯,ansm. Note that for each test case ans0=0. > > You can get the correct input li,ri from what you read (we denote them as l‘i,r‘i)by the following formula: > li=min{(l‘i+ansi−1) mod n+1,(r‘i+ansi−1) mod n+1} > > ri=max{(l‘i+ansi−1) mod n+1,(r‘i+ansi−1) mod n+1} #### 输出 > You should output one single line for each test case. > > For each test case, output one line “Case #x: p1,p2,⋯,pm”, where x is the case number (starting from 1) and p1,p2,⋯,pm is the answer. ####样例输入 > 2 > 5 2 > 3 3 1 5 4 > 2 2 > 4 4 > 5 2 > 2 5 2 1 2 > 2 3 > 2 4
样例输出
Case #1: 3 3
Case #2: 3 1
题意
求区间[l,r]的所有不重复的数(重复的以第一次出现的位置为准)位于中间(位置在中间,不是值)那个数所在的位置。
题目强制在线
题解
用主席树,倒过来建树,从第n个位置建到第1个位置,对于重复的数边做边删,保证只留在最左边的那个,然后对于查询[l,r],我们去查rt[l]那棵树的l,r区间,得到不重复的数有cnt个,然后用求区间第k大的办法去求第(cnt+1)/2大的数。
还有一种思路,每个数存它前驱的位置,然后用主席树求区间[l,r]中比l小的数的个数,从而可以求区间[l,r]内不同的数的个数,然后二分t,去找中间的位置, 这样的复杂度是
nlogn+q*logn*logn
,会卡时间,反正我是t了。
代码
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<sstream>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define mid (l+(r-l)/2)
#define lson(o) (tre[(o)].ls)
#define rson(o) (tre[(o)].rs)
#define sumv(o) (tre[(o)].sum)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;
const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);
//start----------------------------------------------------------------------
const int maxn=201010;
///nlogn空间复杂度
///注意:由于有增加和删除两个操作!所以空间是2n*log(2n)
struct Tre {
int ls,rs,sum;
Tre() {
ls=rs=sum=0;
}
} tre[maxn*50];
int n,m;
int rt[maxn],tot;
int _v,_p;
void update(int &o,int l,int r) {
tre[++tot]=tre[o],o=tot;
if(l==r) {
sumv(o)+=_v;
} else {
if(_p<=mid) update(lson(o),l,mid);
else update(rson(o),mid+1,r);
sumv(o)=sumv(lson(o))+sumv(rson(o));
}
}
///区间内不同的数有几个
int _res,ql,qr;
void query(int o,int l,int r) {
if(ql<=l&&r<=qr) {
_res+=sumv(o);
} else {
if(ql<=mid) query(lson(o),l,mid);
if(qr>mid) query(rson(o),mid+1,r);
}
}
///区间第k大
int _res2;
void query2(int o,int l,int r,int k) {
if(l==r) {
_res2=l;
} else {
if(k<=sumv(lson(o))) query2(lson(o),l,mid,k);
else query2(rson(o),mid+1,r,k-sumv(lson(o)));
}
}
int arr[maxn],mp[maxn];
///0是个超级节点
void init() {
rt[n+1]=tot=0;
}
int main() {
int tc,kase=0;
scf("%d",&tc);
while(tc--) {
scf("%d%d",&n,&m);
init();
for(int i=1; i<=n; i++) {
scf("%d",&arr[i]);
}
///主席树
for(int i=1; i<=n; i++) mp[i]=n+1;
for(int i=n; i>=1; i--) {
rt[i]=rt[i+1];
_v=1,_p=i;
update(rt[i],1,n);
if(mp[arr[i]]<=n) {
_v=-1,_p=mp[arr[i]];
update(rt[i],1,n);
}
mp[arr[i]]=i;
}
int ans=0;
VI lis;
while(m--) {
int ll,rr;
scf("%d%d",&ll,&rr);
int t1=(ll+ans)%n+1,t2=(rr+ans)%n+1;
int l=min(t1,t2),r=max(t1,t2);
///求区间内不同的数有几个
ql=l,qr=r,_res=0;
query(rt[l],1,n);
int k=(_res+1)/2;
///求区间第k大
query2(rt[l],1,n,k);
ans=_res2;
lis.pb(ans);
}
prf("Case #%d:",++kase);
rep(i,0,lis.sz()) {
prf(" %d",lis[i]);
}
putchar('\n');
}
return 0;
}
//end-----------------------------------------------------------------------