BZOJ1878 洛谷1972 HH的项链题解
看到这样不用修改的题目,应该佷容易就联想到了离线来处理。
我们发现若将询问按照r来排序,排完后每次对答案有贡献的仅是每个颜色最后出现的位置
我们用next[i]表示i处颜色之前出现的位置,我们利用树状数组维护每个数最后一次出现的位置小于j的个数,每次的答案就是树状数组l到r这一段的和
显然,next[i]处对答案已经不会产生贡献了,我们就可以将这个贡献减掉
然后再将i处对答案的贡献加入
# include<iostream> # include<cstdio> # include<cmath> # include<algorithm> using std::sort; const int mn = 500005; const int maxn = 200005; inline int read() { int x=0; char ch=getchar(); while(ch>'9' || ch<'0') ch=getchar(); while(ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();} return x; } int n,m; int nxt[1000005],ans[maxn],tmp[1000005]; int T[mn]; //nxt[i]表示在i处的颜色上一次出现的位置 void add(int x,int val) { while(x<=n) { T[x]+=val; x+=(x&-x); } } int sum(int x) { int ret=0; while(x>0) { ret+=T[x]; x-=(x&-x); } return ret; } struct ask{int l,r,id;}; ask b[maxn]; bool cmp(ask x,ask y) { return x.r<y.r; } int main() { int x; n=read(); for(int i=1;i<=n;i++) { x=read(),nxt[i]=tmp[x],tmp[x]=i; } m=read(); for(int i=1;i<=m;i++) b[i].l=read(),b[i].r=read(),b[i].id=i; sort(b+1,b+1+m,cmp); int l=1; for(int i=1;i<=m;i++) { while(l<=b[i].r) { //若上一次出现过,要把上一次统计的结果减掉 if(nxt[l]) add(nxt[l],-1); add(l,1); l++; } ans[b[i].id]=sum(b[i].r)-sum(b[i].l-1); } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }