luogu1972题解

发布时间 2023-12-14 11:04:24作者: LiJoQiao

还是先写被卡的做法吧。
节点的区间用了现用现计算卡常过了。

被卡了一上午,难过。

话说有人说我码风有点抽象。

思路

主席树做法。

a[i] 是贝壳序列。
先求出 nxt,即与 a[i] 相同的下一个 a[j] 的下标 j
p114514[i] 记了值为 \(i\) 的数的下标,循环到序列第 \(j\) 个数的时候,先看看有没有存上一个数的下标,存了就用 locp 存一下,然后更新 p114514[i]

然后对 nxt 建主席树,第 \(i\) 棵树维护一个 01 序列,如果 nxt\(\left[1,i\right]\) 中则标记为 \(0\),否则为 \(1\)。(就是每个线段树代表的其实是一个区间,如果有两个相同值的数在这个区间内会统计下一个忽略上一个)

修改的时候用 locp 存一下每棵线段树要修改的下标,因为每个数和它上一个相等的数是唯一的,如果要修改每次只会修改一个数,开一个数组即可。

每次查询的时候查 root[r] 这颗树上 \(\left[l,r\right]\)\(1\) 的数量即可,不用担心 \(\left[1,l-1\right]\) 这个区间会扣掉树上的一些数,因为记的是 nxt,所以在 \(\left[l,r\right]\) 上不会出现 \(\left[1,l-1\right]\) 区间的数。

写完之后发现可以优化掉 nxt 数组,所以直接去掉了。

代码

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10; 
int n,a[MAXN],tot,locp[MAXN],p114514[MAXN],root[MAXN],m;
struct SegmentTreeNode{
	int sum,lson,rson;
}tr[MAXN<<5];
int read(){
	int x=0;
	char ch=getchar();
	while(ch<'0'||ch>'9'){ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
	return x;
}
namespace sol{
	int newnode(){
		return ++tot;
	}
	int buildtree(int l,int r){
		int p=newnode();
		tr[p].sum=r-l+1;
		if(l==r)return p;
		#define mid ((l+r)>>1)
		tr[p].lson=buildtree(l,mid);
		tr[p].rson=buildtree(mid+1,r);
		#undef mid
		return p;
	}
	void change(int p1,int &p2,int loc,int l,int r){
		p2=newnode();
		tr[p2].sum=tr[p1].sum-1;
		if(l==r)return;
		#define mid ((l+r)>>1)
		if(loc<=mid){
			change(tr[p1].lson,tr[p2].lson,loc,l,mid);
			tr[p2].rson=tr[p1].rson;
		}else{
			tr[p2].lson=tr[p1].lson;
			change(tr[p1].rson,tr[p2].rson,loc,mid+1,r);
		}
		#undef mid
	}
	int query(int p,int l,int r,int l1,int r1){
		if(l1==l&&r1==r)return tr[p].sum;
		#define mid ((l1+r1)>>1)
		if(r<=mid)return query(tr[p].lson,l,r,l1,mid);
		else if(mid<l)return query(tr[p].rson,l,r,mid+1,r1);
		else return query(tr[p].lson,l,mid,l1,mid)+query(tr[p].rson,mid+1,r,mid+1,r1);
		#undef mid 
	}
	void solve(){
		n=read();
		for(int i=1;i<=n;++i){
			a[i]=read();
		}
		root[1]=buildtree(1,n);
		for(int i=1;i<=n;++i){
			locp[i]=p114514[a[i]];
			p114514[a[i]]=i;
		}
		for(int i=2;i<=n;++i){
			root[i]=root[i-1];
			if(locp[i]!=0)
				change(root[i-1],root[i],locp[i],1,n);
		}
		m=read();
		while(m){
			--m;
			int l,r;
			l=read();r=read();
			printf("%d\n",query(root[r],l,r,1,n));
		}
	}
}
int main(){
	sol::solve();
	return 0;
}

讨厌卡常啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊