您的位置:首页 > 产品设计 > UI/UE

HDU 5919 Sequence II 主席树

2016-10-05 23:13 381 查看

题目链接:

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

Sequence II

Time Limit: 9000/4500 MS (Java/Others)Memory Limit: 131072/131072 K (Java/Others)

问题描述


Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,⋯,an There are m queries.

In the i-th query, you are given two integers li and ri. Consider the subsequence ali,ali+1,ali+2,⋯,ari.

We can denote the positions(the positions according to the original sequence) where an integer appears first in this subsequence as p(i)1,p(i)2,⋯,p(i)ki (in ascending order, i.e.,p(i)1<p(i)2<⋯<p(i)ki).

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-----------------------------------------------------------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: