题目链接:[SDOI2009]HH的项链 - 洛谷
第一次做离线算法的题目,记录一下。思路参考:题解 P1972 【[SDOI2009]HH的项链】 - dlhham 的博客 - 洛谷博客
离线算法的本质是什么?是当一开始就已知所有要回答的问题的时候,把问题进行一定的排序, 然后逐个给出答案。排序的目的是使得后面的问题能用上前面得到的结论,从而减少复杂度。
考虑按照询问区间的右端点排序。对于每个问题,记录开始位置到当前右端点的所有数字的最靠右的位置,用树状数组或者线段树记录区间的贡献(对于每个点,如果是某个数字的最右位置,那么贡献为1,否则为0)
code1:树状数组
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define For(i, a, b) for (int i = (a); i <= (b); i++)
const int N = 1e6+5;
struct Q{int l,r,id;} q[N];
int n,m,a[N],t[N],pre[N],ans[N];
bool cmp(const Q&a,const Q&b){return a.r<b.r;}
inline int lowbit(int x){return x&-x;}
inline void add(int p,int x){
for(; p<=n; p+=lowbit(p))
t[p]+=x;
}
inline int query(int p){
int res=0;
for(; p; p-=lowbit(p)) res+=t[p];
return res;
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin>>n; For(i,1,n) cin>>a[i];
cin>>m; For(i,1,m) cin>>q[i].l>>q[i].r, q[i].id=i;
sort(q+1,q+m+1,cmp);
int cur=0;
For(i,1,m){
while(cur<q[i].r){
cur++;
if(pre[a[cur]]) add(pre[a[cur]],-1); //如果之前出现过这个数字,就删去它的影响
add(cur,1); pre[a[cur]]=cur; //记录最后一个位置
}
ans[q[i].id]=query(q[i].r)-query(q[i].l-1);
}
For(i,1,m) cout<<ans[i]<<'\n';
}
code2:线段树(代码长一丢丢,本质方法一样)
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define For(i, a, b) for (int i = (a); i <= (b); i++)
const int N = 1e6+5;
struct Q{int l,r,id;} q[N];
int n,m,a[N],t[N<<2],pre[N],ans[N];
bool cmp(const Q&a,const Q&b){return a.r<b.r;}
void upd(int p,int l,int r,int pos,int x){
if(l==r) {t[p]=x; return;}
int mid = l+r>>1;
if(pos<=mid) upd(p<<1,l,mid,pos,x);
else upd(p<<1|1,mid+1,r,pos,x);
t[p] = t[p<<1]+t[p<<1|1];
}
int query(int p,int l,int r,int x,int y){
if(x<=l && r<=y) return t[p];
int mid=l+r>>1, ans=0;
if(x<=mid) ans+=query(p<<1,l,mid,x,y);
if(y>mid) ans+=query(p<<1|1,mid+1,r,x,y);
return ans;
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin>>n; For(i,1,n) cin>>a[i];
cin>>m; For(i,1,m) cin>>q[i].l>>q[i].r, q[i].id=i;
sort(q+1,q+m+1,cmp);
int cur=0;
For(i,1,m){
while(cur<q[i].r){
cur++;
if(pre[a[cur]]) upd(1,1,n,pre[a[cur]],0);
upd(1,1,n,cur,1); pre[a[cur]]=cur;
}
ans[q[i].id]=query(1,1,n,q[i].l,q[i].r);
}
For(i,1,m) cout<<ans[i]<<'\n';
}