博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

SDOI2009 HH的项链

题目大意

给定一个序列,求区间出现次数为1次的数字有多少?

\(n \leq 10^6\)

思路一

首先处理出第\(i\)个数上次出现的位置pre,维护一个权值数组表示到第\(i\)个位置时的数字分布情况。

处理一个区间时就是对于右端点为r时,\(l \leq a[i] \leq r,pre[a[i]] < l\)记录即可

由于答案具有前缀和性质,用树状数组维护即可。

代码一

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int pre[N];
int n;
int c[N];
int a[N];
int l,r;
int m;
int ans[N];
struct node {
	int id;
	int pos;
	node (int _id,int _pos) {
		id = _id;
		pos = _pos;
	}
};

vector <node> q[N];
int lowbit(int x) {
	return x & -x;
}

void modify(int x,int v) {
	while(x <= n) {
		c[x] += v;
		x += lowbit(x);
	}
}

int query(int x) {
	int ans = 0;
	while(x) {
		ans += c[x];
		x -= lowbit(x);
	}
	return ans;
}

int main () {
	cin >> n;
	for(int i = 1;i <= n; i ++) cin >> a[i];
	cin >> m;
	for(int i = 1;i <= m; i ++) {
		cin >> l >> r;
		q[r].push_back(node(i,l));
	}
	for(int i = 1;i <= n; i ++) {
		if(pre[a[i]]) {
			modify(pre[a[i]],-1);
			modify(i,1);
			pre[a[i]] = i;
		}
		else {
			modify(i,1);
			pre[a[i]] = i;
		}
		for(int j = 0;j < q[i].size(); j ++) {
			node y = q[i][j];
			ans[y.id] = query(i) - query(y.pos - 1);
		}
	}
	for(int i = 1;i <= m; i ++) {
		cout << ans[i] << endl;
	}
	return 0;
}

思路二

同思路一情况,需维护数组pre,使用主席树在线维护即可。

代码二

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
const int M = (N << 2) + 30;

int rt[M];
int w[N];
int last[N];
struct kcj_seg_tree {
	int sum[M];
	int lch[M];
	int rch[M];
	int tot = 0;
	void build(int l,int r,int &root) {
		root = ++tot;
		if(l == r) {
			return;
		}
		int mid = (l + r) >> 1;
		build(l,mid,lch[root]);
		build(mid + 1,r,rch[root]);
	}
	void insert(int l,int r,int &root,int old,int pos) {
		root = ++tot;
		lch[root] = lch[old];
		rch[root] = rch[old];
		sum[root] = sum[old];
		if(l == r) {
			sum[root] ++;
			return;
		}
		int mid = (l + r) >> 1;
		if(pos <= mid) {
			insert(l,mid,lch[root],lch[old],pos);
		}
		else insert(mid + 1,r,rch[root],rch[old],pos);
		sum[root] = sum[lch[root]] + sum[rch[root]];
	}

	int query(int l,int r,int s,int t,int x) {
		if(l == r) {
			return sum[t] - sum[s];
		}
		int mid = (l + r)  >> 1;
		int _s = sum[lch[t]] - sum[lch[s]];
		if(x <= mid) {
			return query(l,mid,lch[s],lch[t],x);
		}
		else {
			return _s + query(mid + 1,r,rch[s],rch[t],x);
		}
	}
} ST;
int n,m;
int main () {
	scanf("%d",&n);
	for (int i = 1;i <= n; i ++) {
		int x;
		scanf("%d",&x);
		w[i] = last[x];
		last[x] = i;
	}
	ST.build(1,n,rt[0]);
	for(int i = 1;i <= n; i ++) {
		ST.insert(1,n,rt[i],rt[i - 1],w[i] + 1);
	}
	scanf("%d",&m);
	while(m --) {
		int l,r;
		scanf("%d %d",&l,&r);
		int ans = ST.query(1,n,rt[l - 1],rt[r],l);
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2022-02-16 18:31  Allorkiya  阅读(21)  评论(0编辑  收藏  举报