(重新组队后的第一场组队赛 也是和自己队友的一次磨合吧
这场比赛真的算是一个下马威吧……队友上手一看 啊这不是莫队嘛 然后开敲 敲完提交发现t了 在改完了若干个坑点后还是依然t(真是一个悲伤的故事)然后换我上去查 在经历了一番玄幻操作之后 不知为啥就过了……
J Different Integers
题目大意就是一个数组, 长度n<=1e5 q次询问(l, r) 输出区间[1, l] [r, n]中不同数字的个数 q<=1e5
一开始上了莫队的板子 但是t掉了 后来发现题目中有个隐藏的坑点 就是存在l>r的情况
找出坑点后 发现还是t 就想到估计要有优化 在分块的时候不用从头到尾进行分块 这也是一个t的点
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <cctype>
#include <ctime>
#include <map>
using namespace std;
const int maxn=1e5+;
int a[maxn];
int sum[maxn];
int num[maxn];
int n,q,now;
struct Node{
int l,r,id,d;
}node[maxn];
bool cmp1(Node one,Node two){
if(one.d!=two.d){
return one.d<two.d;
}else{
return one.r<two.r;
}
}
int main(){
while(~scanf("%d%d",&n,&q)){
int all=;
for(int i=;i<=n;i++) {
scanf("%d",&a[i]);num[a[i]]++;
if(num[a[i]]==){
all++;
}
}
int tmp=all;
int block=sqrt(n)+;
for(int i=;i<=q;i++){
scanf("%d%d",&node[i].l,&node[i].r);
node[i].l++;
node[i].r--;
node[i].d=node[i].l/block+;
node[i].id=i;
}
sort(node+,node++q,cmp1);
int l=,r=;
for(int i=;i<=q;i++){
if(node[i].l>node[i].r) {sum[node[i].id]=tmp;continue;}
while(l<node[i].l){
num[a[l]]++;
if(num[a[l]]==) all++;l++;
}
while(l>node[i].l){
l--;num[a[l]]--;
if(num[a[l]]==) all--;
}
while(r<node[i].r){
r++;
num[a[r]]--;
if(num[a[r]]==) all--;
}
while(r>node[i].r){
num[a[r]]++;
if(num[a[r]]==) all++;r--;
}
sum[node[i].id]=all;
}
for(int i=;i<=q;i++){
printf("%d\n",sum[i]);
}
for(int i=;i<=n;i++){
num[a[i]]=;
}
}
return ;
}
后来看叉姐直播讲解的时候 发现还可以用树状数组 线段树去做 好像卡掉了主席树 因为必须要离线状态 下次研究一下树状数组的做法 同时蔡队还在弹幕中提出了一个做法 感觉很巧妙 这里也分享一下 就是把原数组扩展成两倍的长度 首位拼接 所以1-l r-n就变成了r-l+n 就直接是区间问题了(就可以愉快的套板子了)(留坑 研究完就上传代码)
弱鸡队艰难签到成功后 在a题和d题卡了数不清的时间 等补题完后再来填坑orz