一、题目描述:

链接: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=;
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 += ;
while(a<n+)
{
arr_1[a].arr.push_back(b);
a += a &(-a);
}
} int count(int a,int b)
{
// cout<<"query: "<<a<<" "<<b<<endl;
a += ;
int cnt = ; 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 = ;
memset(first,-,sizeof(first));
memset(last,-,sizeof(last));
p.clear();
for(int i=;i<n;++i)scanf("%d",&arr[i]);//cin>>arr[i];
for(int i=;i<n+;++i)arr_1[i].arr.clear();
for(int i=;i<n;++i)
{
int a = i;
int b = n--i;
int ta = arr[a];
int tb = arr[b];
if(first[ta] == -)
{
summ++;
first[ta] = a;
if(last[ta] != -)
p.push_back(make_pair(first[ta],last[ta]));
}
if(last[tb] == -)
{
last[tb] = b;
if(first[tb]!= -)
p.push_back(make_pair(first[tb],last[tb]));
}
}
sort(p.begin(),p.end(),cmp);
int len = p.size();
for(int i=;i<len;++i)
{
insert(p[i].first,p[i].second);
}
for(int i=;i<m;++i)
{
int a,b;
// cin>>a>>b;
scanf("%d%d",&a,&b);
a--;b--;
cout<<summ-(count(b-,b) - count(a,b))<<"\n";
} } int main()
{ while(cin>>n>>m)init(); return ;
}

最新文章

  1. ORACLE_UNQNAME
  2. Rock-Paper-Scissors Tournament[HDU1148]
  3. 我的CSS样式记事本(1)
  4. Ubuntu Nginx搭建Gitweb服务器
  5. 通用PE u盘装Ghost Win7系统
  6. 使用 Azure Site Recovery 将内部部署虚拟化工作负荷迁移至 Azure
  7. LinkCode 下一个排列、上一个排列
  8. angular.js的表格指令
  9. 第二篇--上传git 代码
  10. Python中的常用魔术方法介绍
  11. @Autowired注解和静态方法
  12. 【SQL】数据库中的五种约束
  13. 有关centos7 图形化root用户登录
  14. hdu3400(三分套三分)
  15. 开发板测试-Wi-Fi
  16. sql 之 INSERT IGNORE
  17. Redis学习第八课:Redis高级实用特性(二)
  18. 使用FluentScheduler实现定时任务管理
  19. linux rz sz 的安装
  20. 一个iframe注入漏洞,也是微软的 Application[&quot;error&quot;] 漏洞

热门文章

  1. dojo事件绑定
  2. Python 爬虫实战(二):使用 requests-html
  3. Java—多态
  4. 笨办法学Python(八)
  5. PHP : 封装跳转函数,实现三个页面的跳转
  6. Javascript作业—封装type函数,返回较详细的数据类型
  7. 砍树,POJ(2665)
  8. CentOS系统中使用iptables设置端口转发
  9. c# base new 等关键字基础
  10. 线程 task pritce