SPOJ 3267 D-query(离散化+在线主席树 | 离线树状数组)

时间:2023-03-08 18:29:44
SPOJ 3267 D-query(离散化+在线主席树 | 离线树状数组)

DQUERY - D-query

English Vietnamese

Given a sequence of n numbers a1, a2, ..., an and a number of d-queries. A d-query is a pair (i, j) (1 ≤ i ≤ j ≤ n). For each d-query (i, j), you have to return the number of distinct elements in the subsequence ai, ai+1, ..., aj.

Input

  • Line 1: n (1 ≤ n ≤ 30000).
  • Line 2: n numbers a1, a2, ..., an (1 ≤ ai ≤ 106).
  • Line 3: q (1 ≤ q ≤ 200000), the number of d-queries.
  • In the next q lines, each line contains 2 numbers i, j representing a d-query (1 ≤ i ≤ j ≤ n).

Output

  • For each d-query (i, j), print the number of distinct elements in the subsequence ai, ai+1, ..., aj in a single line.

Example

Input
5
1 1 2 1 3
3
1 5
2 4
3 5 Output
3
2
3

题目链接:SPOJ 3267

假设数组从1开始,以当前数字的位置(下标)为pos,贡献为1,用主席树维护前缀序列[1,i]的贡献和,则显然第i棵线段树就是对应的前缀序列[1,i],

有两种情况,这个数字之前出现过,比如6 6 6 2 3,扫到第二个1的时候发现lastpos中6的位置为1,则先把上一次的树拿来作一次更新,更新所得到的根储存在temp里,再把temp作为上一次的依存根,以root[i]现在的根进行更新,即重新定位了6的位置,总体来说就是每一次把出现过的数字位置都维护成最新的再配合主席树

题目给出l与r,r可直接用,显然l还不对需要转换,我这里写的和其他人的做法不太一样,还是用区间内的区间求和思想。即对root[l-1]~root[r]求l~r的区间和。因为用的是下标而不是原值更不是离散化之后的值作插入位置,因此l,r既是询问区间也是求和区间。一开始范围搞错了把离散化之后的size作为值域大小,wa数次……,此外这题似乎还可以莫队或者离线树状数组搞搞,前者太模版了懒的写,后者理解不够深入就先不贴代码了,最近学了下离线树状数组,发现可以搞的1A过了,而且时间比主席树快

主席树代码:

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
typedef pair<int,int> pii;
typedef long long LL;
const double PI=acos(-1.0);
const int N=30010;
struct seg
{
int lson,rson;
int cnt;
};
seg T[N*20];
int root[N],tot;
vector<int>pos;
int arr[N];
int last_pos[N]; void init()
{
pos.clear();
CLR(root,0);
tot=0;
T[0].cnt=T[0].lson=T[0].rson=0;
CLR(last_pos,0);
}
void update(int &cur,int ori,int l,int r,int pos,int flag)
{
cur=++tot;
T[cur]=T[ori];
T[cur].cnt+=flag;
if(l==r)
return ;
int mid=MID(l,r);
if(pos<=mid)
update(T[cur].lson,T[ori].lson,l,mid,pos,flag);
else
update(T[cur].rson,T[ori].rson,mid+1,r,pos,flag);
}
int query(int S,int E,int l,int r,int x,int y)
{
if(x<=l&&r<=y)
return T[E].cnt-T[S].cnt;
else
{
int mid=MID(l,r);
if(y<=mid)
return query(T[S].lson,T[E].lson,l,mid,x,y);
else if(x>mid)
return query(T[S].rson,T[E].rson,mid+1,r,x,y);
else
return query(T[S].lson,T[E].lson,l,mid,x,mid)+query(T[S].rson,T[E].rson,mid+1,r,mid+1,y);
}
}
int main(void)
{
int n,m,i,l,r;
while (~scanf("%d",&n))
{
init();
for (i=1; i<=n; ++i)
{
scanf("%d",&arr[i]);
pos.push_back(arr[i]);
}
scanf("%d",&m);
sort(pos.begin(),pos.end());
pos.erase(unique(pos.begin(),pos.end()),pos.end());
int temp_rt=0;
for (i=1; i<=n; ++i)
{
arr[i]=lower_bound(pos.begin(),pos.end(),arr[i])-pos.begin()+1;
if(!last_pos[arr[i]])
{
update(root[i],root[i-1],1,n,i,1);
last_pos[arr[i]]=i;
}
else
{
update(temp_rt,root[i-1],1,n,last_pos[arr[i]],-1);
update(root[i],temp_rt,1,n,i,1);
last_pos[arr[i]]=i;
}
}
for (i=0; i<m; ++i)
{
scanf("%d%d",&l,&r);
printf("%d\n",query(root[l-1],root[r],1,n,l,r));
}
}
return 0;
}

离线树状数组代码:

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
typedef pair<int, int> pii;
typedef long long LL;
const double PI = acos(-1.0);
const int N = 30010;
const int M = 200010;
struct info
{
int k, l, r, flag, id;
info() {}
info(int _k, int _l, int _r, int _flag, int _id): k(_k), l(_l), r(_r), flag(_flag), id(_id) {}
bool operator<(const info &rhs)const
{
return k < rhs.k;
}
};
info Q[M << 1];
int T[N], ans[M];
int arr[N], last[N];
vector<int>xpos; void init()
{
CLR(T, 0);
CLR(ans, 0);
CLR(last, 0);
xpos.clear();
}
void add(int k, int v)
{
while (k < N)
{
T[k] += v;
k += (k & -k);
}
}
int getsum(int k)
{
int ret = 0;
while (k)
{
ret += T[k];
k -= (k & -k);
}
return ret;
}
int main(void)
{
int n, m, i;
while (~scanf("%d", &n))
{
init();
for (i = 1; i <= n; ++i)
{
scanf("%d", &arr[i]);
xpos.push_back(arr[i]);
}
sort(xpos.begin(), xpos.end());
xpos.erase(unique(xpos.begin(), xpos.end()), xpos.end());
for (i = 1; i <= n; ++i)
arr[i] = lower_bound(xpos.begin(), xpos.end(), arr[i]) - xpos.begin() + 1;
scanf("%d", &m);
int qcnt = 0;
for (i = 0; i < m; ++i)
{
int l, r;
scanf("%d%d", &l, &r);
Q[qcnt++] = info(l, l, r, 0, i);
Q[qcnt++] = info(r, l, r, 1, i);
}
sort(Q, Q + qcnt);
int x = 1;
for (i = 0; i < qcnt; ++i)
{
while (x <= Q[i].k)
{
int val = arr[x];
if (!last[val])
add(x, 1);
else
{
add(last[val], -1);
add(x, 1);
}
last[val] = x;
++x;
}
if (Q[i].flag)
ans[Q[i].id] += getsum(Q[i].r) - getsum(Q[i].l - 1);
else//实际上这里可以再优化,在l-1之外的求和肯定为0,这里可以不需要的
{
add(last[arr[x - 1]], -1);
ans[Q[i].id] -= getsum(Q[i].r) - getsum(Q[i].l - 1);
add(last[arr[x - 1]], 1);
}
}
for (i = 0; i < m; ++i)
printf("%d\n", ans[i]);
}
return 0;
}