标签:
题解:
神一样的树状数组题目,首先m很大,先离线处理,按照r从小到大排序,预处理每个数前一次出现的位置,第一次为0,pre数组保存
按照每个询问从左到右枚举a[n]。
接下来,对于位置i上对应的数.只有在l它上一次的位置出现的前面(记为p)才能够增加。所以树状数组更新从1到p,加1,但是>=2次都只算一次,所以把上上一次更新(记为pp)的减去,即树状数组从1到pp减1
好神奇
代码:
#include<bits/stdc++.h> using namespace std; #define pb push_back #define mp make_pair #define se second #define fs first #define ll long long #define CLR(x) memset(x,0,sizeof x) #define MC(x,y) memcpy(x,y,sizeof(x)) #define SZ(x) ((int)(x).size()) #define FOR(it,c) for(__typeof((c).begin()) it=(c).begin();it!=(c).end();it++) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define INF 2097152 typedef pair<int,int> P; const double eps=1e-9; const int maxn=1000100; const int mod=1e9+7; ll read() { ll x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } //----------------------------------------------------------------------------- bool cmp(P a,P b) { if(a.se==b.se) return a.fs<b.fs; return a.se<b.se; } P p[maxn],s[maxn]; int a[maxn],pre[maxn],c[maxn],last[maxn]; map<P,int> ans; void add(int x,int d) { while(x) { c[x]+=d; x-=(x&-x); } } int sum(int x) { int cnt=0; while(x<maxn) { cnt+=c[x]; x+=(x&-x); } return cnt; } int main() { int n,c,m; cin>>n>>c>>m; for(int i=1;i<=n;i++) { a[i]=read(); pre[i]=last[a[i]]; last[a[i]]=i; } for(int i=1;i<=m;i++) { p[i].fs=read();p[i].se=read(); s[i]=p[i]; } sort(p+1,p+m+1,cmp); int r=1; for(int i=1;i<=m;i++) { while(r<=p[i].se) { add(pre[pre[r]],-1); add(pre[r],1); r++; } ans[p[i]]=sum(p[i].fs); } for(int i=1;i<=m;i++) printf("%d\n",ans[s[i]]); return 0; }
标签:
原文地址:http://www.cnblogs.com/byene/p/5746907.html