BZOJ 1878(离散化+线段树)
题面
分析
首先我们观察到区间范围较大,而区间个数较少,考虑离散化,将所有询问按照右端点进行排序
离散化之后研究区间颜色个数变化的规律
当我们处理到第a[i]个段时,设a[i]上一次出现的地方为last[a[i]],则last[a[i]]之前的颜色出现次数不受影响.
首先遍历右端点范围r,用线段树维护每一位到r的区间中有多少种颜色,记为c
则处理到第a[i]个段时,将(last[a[i]],i]区间+1
如r=6时
a={3,1,5,2,4,1}
处理第6位之前c={5,4,3,2,1,0}
last[a[6]]=2,然后将区间(2,6]+1
c={5,5,4,3,2,1}
此时,在询问中找右端点为r的询问[l,r],答案即为c[l]
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxn 50005
#define maxm 200005
using namespace std;
int n,m;
struct node{//标准的线段树
int l;
int r;
int mark;
int v;
int len(){
return r-l+1;
}
}tree[maxn<<2];
void push_up(int pos){
tree[pos].v=tree[pos<<1].v+tree[pos<<1|1].v;
}
void build(int l,int r,int pos){
tree[pos].l=l;
tree[pos].r=r;
tree[pos].mark=0;
tree[pos].v=0;
if(l==r){
tree[pos].v=0;
return;
}
int mid=(l+r)>>1;
build(l,mid,pos<<1);
build(mid+1,r,pos<<1|1);
push_up(pos);
}
void push_down(int pos){
if(tree[pos].mark){
tree[pos<<1].mark+=tree[pos].mark;
tree[pos<<1|1].mark+=tree[pos].mark;
tree[pos<<1].v+=tree[pos].mark*tree[pos<<1].len();
tree[pos<<1|1].v+=tree[pos].mark*tree[pos<<1|1].len();
tree[pos].mark=0;
}
}
void update(int L,int R,int v,int pos){
if(L<=tree[pos].l&&R>=tree[pos].r){
tree[pos].v+=v*tree[pos].len();
tree[pos].mark+=v;
return;
}
push_down(pos);
int mid=(tree[pos].l+tree[pos].r)>>1;
if(L<=mid) update(L,R,v,pos<<1);
if(R>mid) update(L,R,v,pos<<1|1);
push_up(pos);
}
int query(int L,int R,int pos){
if(L<=tree[pos].l&&R>=tree[pos].r){
return tree[pos].v;
}
push_down(pos);
int mid=(tree[pos].l+tree[pos].r)>>1;
int ans=0;
if(L<=mid) ans+=query(L,R,pos<<1);
if(R>mid) ans+=query(L,R,pos<<1|1);
return ans;
}
int bin_search(int l,int r,int x,int *a){//二分查找,离散化用
int mid;
while(l<=r){
mid=(l+r)>>1;
if(a[mid]==x) return mid;
else if(a[mid]>x) r=mid-1;
else l=mid+1;
}
return -1;
}
int a[maxn],b[maxn];
int last[maxn];
struct ask{
int l;
int r;
int i;
}q[maxm];
int ans[maxm];
int cmp(ask x,ask y){
return x.r==y.r?x.l<y.l:x.r<y.r;//按右端点排序
}
int main(){
int l,r;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+1+n);
int n2=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++){
a[i]=bin_search(1,n2,a[i],b);
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d %d",&q[i].l,&q[i].r);
q[i].i=i;
}
sort(q+1,q+1+m,cmp);
int cnt=1;
build(1,n,1);
for(int i=1;i<=n;i++){//遍历右端点i
update(last[a[i]]+1,i,1,1);
last[a[i]]=i;
while(q[cnt].r==i){
ans[q[cnt].i]=query(q[cnt].l,q[cnt].l,1);//要按排序前的顺序输出
cnt++;
}
if(cnt>m) break;
}
for(int i=1;i<=m;i++) printf("%d ",ans[i]);
}
版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢