牛客暑假多校第一场J-Different Integers
一、题目描述:
链接:https://www.nowcoder.com/acm/contest/139/J
Given a sequence of integers a1, a2, ..., an and q pairs of integers (l1, r1), (l2, r2), ..., (lq, rq), find count(l1, r1), count(l2, r2), ..., count(lq, rq) where count(i, j) is the number of different integers among a1, a2, ..., ai, aj, aj + 1, ..., an.
大概是说,给一个长为n的数组,要求进行m次查询,每次给出l,r要求统计数组内,除了(l,r)区间内的其他元素的种类数。
二、思路
考虑一个元素有两个属性:第一次出现的地方和最后一次出现的地方:记为first[x]和last[x]
则答案应为,总元素个数 - 只在给定区间内出现的元素个数。
则问题实际上转化为 求count(first[x],last[x] ∈ (l,r))。
考虑实际上对于每个元素来说,first[x],和last[x]可以理解为二元组——或者二维空间的坐标,则问题实际转化为二维空间内的点统计问题。因为元素太多,所以考虑使用主席树的方式来构造二维线段树。
但是进一步观察可得,每一行每一列都只有一个元素可能存在。于是如果保证二元组(first[x],last[x])中last[x]保持递增顺序其实就没必要一定要构造主席树来进行数字统计——直接用树状数组挂vector之后用lower_bound查出现位置即可。
#include<bits/stdc++.h> using namespace std; #define pp pair<int,int> #define veci vector<int> #define vecp vector<pp> const int MAXN=100233; vecp p; int first[MAXN]; int last[MAXN]; int arr[MAXN]; int n,m; int summ ; class Node { public: veci arr; }; Node arr_1[MAXN]; void insert(int a,int b) { // cout<<a<<" "<<b<<endl; a += 10; while(a<n+23) { arr_1[a].arr.push_back(b); a += a &(-a); } } int count(int a,int b) { // cout<<"query: "<<a<<" "<<b<<endl; a += 10; int cnt = 0; while(a) { int tmp = lower_bound(arr_1[a].arr.begin(),arr_1[a].arr.end(),b)-arr_1[a].arr.begin(); // if(tmp != arr_1[a].arr.size() && arr_1[a].arr[tmp] == b)tmp ++; cnt += tmp; // cout<< "tmp: "<<tmp<<" size"<<arr_1[a].arr.size()<<endl; a-=a&(-a); } return cnt; } bool cmp(pp p1,pp p2) { return p1.second<p2.second; } void init() { summ = 0; memset(first,-1,sizeof(first)); memset(last,-1,sizeof(last)); p.clear(); for(int i=0;i<n;++i)scanf("%d",&arr[i]);//cin>>arr[i]; for(int i=0;i<n+23;++i)arr_1[i].arr.clear(); for(int i=0;i<n;++i) { int a = i; int b = n-1-i; int ta = arr[a]; int tb = arr[b]; if(first[ta] == -1) { summ++; first[ta] = a; if(last[ta] != -1) p.push_back(make_pair(first[ta],last[ta])); } if(last[tb] == -1) { last[tb] = b; if(first[tb]!= -1) p.push_back(make_pair(first[tb],last[tb])); } } sort(p.begin(),p.end(),cmp); int len = p.size(); for(int i=0;i<len;++i) { insert(p[i].first,p[i].second); } for(int i=0;i<m;++i) { int a,b; // cin>>a>>b; scanf("%d%d",&a,&b); a--;b--; cout<<summ-(count(b-1,b) - count(a,b))<<"\n"; } } int main() { while(cin>>n>>m)init(); return 0; }