D-query 树状数组离线(区间不同数个数)

it2023-06-25  67

原题链接 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

题意:

输入n个数,q个询问,每次询问给一个区间【l-r】,求这个区间不同数个数。

题解

没有修改操作。先将所有询问的左右区间读入结构体数组q中,并记录下id(读入顺序)。对区间右端点从小到大排序。依次处理每个区间。 当某个数之前出现过。则将这个数之前的下标add(i,-1),然后用map更新这个数的下标(同一个数保存最靠r的下标)。给这个新的下标add(i,1) 比如13415,不管我查询【1-5】或是【4-5】,1都只统计了一次。

#include<bits/stdc++.h> using namespace std; const int N=2e5+10; int a[N],tr[N],ans[N]; map<int,int>mp;//存某个数的下标 int n,m; struct node { int l,r,id;//区间做右端点,询问的编号 } q[N]; bool cmp(node x,node y) { return x.r<y.r;//右区间小到大排序 } int lowbit(int x) { return x&-x; } void add(int x,int c) { for(int i=x;i<=n;i+=lowbit(i))tr[i]+=c; } int sum(int x) { int res=0; for(int i=x;i;i-=lowbit(i))res+=tr[i]; return res; } int main() { cin>>n; for(int i=1; i<=n; i++)cin>>a[i]; cin>>m; for(int i=1; i<=m; i++) { scanf("%d %d",&q[i].l,&q[i].r); q[i].id=i; } sort(q+1,q+1+m,cmp); int cur=1; for(int i=1; i<=m; i++) { for(int j=cur; j<=q[i].r; j++) { if(mp.count(a[j]))add(mp[a[j]],-1); //这个数之前出现过了,把之前的下标-1 mp[a[j]]=j;//更新下标 add(j,1); } cur=q[i].r+1;//下次从这个区间右端点的下一个点开始 ans[q[i].id]=sum(q[i].r)-sum(q[i].l-1); } for(int i=1;i<=m;i++)printf("%d\n",ans[i]); return 0; }
最新回复(0)