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;
}