P1972【SDOI2009】HH的项链 题解

写这篇题解主要是因为这个题的离线方法比较典。

考虑到如果我们对每个珍珠从左向右看的话,那么对于每种珍珠有效的就只有最右边的那一个,然后我们只需要把区间按右端点排序,然后从 \(1\)\(n\) 扫一遍,每扫到一个珍珠,就把这个珍珠出现的前一个位置的线段树上的值修改为 \(0\),当前这个位置修改为 \(1\),这样每个节点存放的值都是有效的,然后查询区间和就行了。

\(1\)\(n\) 扫一遍,然后操作,这是一个较为常见的离线方法。例如CF1000F。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
using namespace std;
const int N=1e6+10;
int n,a[N],m,pre[N],tree[N<<2],ans[N];
struct que{int l,r,id;}q[N];
bool cmp(que a,que b)
{
	if(a.r==b.r)return a.l<b.l;
	return a.r<b.r;
}
void update(int p,int pl,int pr,int pos,int x)
{
	if(pl==pr){tree[p]=x;return;}
	int mid=(pl+pr)>>1;
	if(pos<=mid)update(ls(p),pl,mid,pos,x);
	else update(rs(p),mid+1,pr,pos,x);
	tree[p]=tree[ls(p)]+tree[rs(p)];
}
int query(int p,int pl,int pr,int L,int R)
{
	if(L<=pl&&pr<=R)return tree[p];
	int mid=(pl+pr)>>1,res=0;
	if(L<=mid)res+=query(ls(p),pl,mid,L,R);
	if(R>mid)res+=query(rs(p),mid+1,pr,L,R);
	return res;
}
int main()
{
	ios::sync_with_stdio(0);
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i],pre[a[i]]=-1;
	cin>>m;
	for(int i=1;i<=m;i++)cin>>q[i].l>>q[i].r,q[i].id=i;
	sort(q+1,q+1+m,cmp);
	for(int i=1,j=1;i<=n;i++)
	{
		if(pre[a[i]]!=-1)update(1,1,n,pre[a[i]],0);
		pre[a[i]]=i;update(1,1,n,i,1);for(;q[j].r<i;j++);
		for(;q[j].r==i;j++)ans[q[j].id]=query(1,1,n,q[j].l,q[j].r);
	}
	for(int i=1;i<=m;i++)cout<<ans[i]<<"\n";
	return 0;
}
posted @ 2024-01-29 11:15  lhc0707  阅读(25)  评论(0编辑  收藏  举报