1 条题解
-
0
本题有一个比较显然的莫队做法,时间复杂度 ,可以过,但这里不讲。
先不考虑去重的条件,如果是第 个测试点,那么发现答案可以前缀和,直接对 和 离线一下,就可以直接统计答案了。
考虑对 离线,统计所有右端点位 的答案。
那么如果有一堆 ,我显然只取最后面的。
那么我只需要支持动态加数删数,查询前缀的一个字典树上和。
这个可以直接用树状数组套字典树,时间复杂度 。
代码
#include<bits/stdc++.h> using namespace std; const int N=1e5+5; int n,a[N],s[N*330],tr[N*330][2],Q,ans[N],las[N],tot,rt[N]; struct que{int l,a,b,id;}; vector<que> vec[N]; void add(int now,int x,int z){ for(int i=20;i>=0;i--){ s[now]+=z; int bit=(x>>i)&1; if(!tr[now][bit])tr[now][bit]=++tot; now=tr[now][bit]; } s[now]+=z; } int ask(int now,int x,int k){ int ans=0; for(int i=20;i>=0;i--){ if(!now)return ans; int bitx=(x>>i)&1,bitk=(k>>i)&1; if(bitk)ans+=s[tr[now][bitx]],now=tr[now][bitx^1]; else now=tr[now][bitx]; } return ans+s[now]; } void tradd(int x,int z,int id){for(;x<=n;x+=x&-x)add(rt[x],id,z);} int trask(int x,int a,int b){int ans=0;for(;x;x-=x&-x)ans+=ask(rt[x],a,b);return ans;} int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); scanf("%d",&Q); for(int i=1;i<=n;i++)rt[i]=i; tot=n; for(int i=1,l,r,A,B;i<=Q;i++)scanf("%d%d%d%d",&l,&r,&A,&B),vec[r].push_back((que){l,A,B,i}); for(int i=1;i<=n;i++){ if(las[a[i]])tradd(las[a[i]],-1,a[i]); tradd(i,1,a[i]); las[a[i]]=i; for(auto j:vec[i])ans[j.id]=trask(i,j.a,j.b)-trask(j.l-1,j.a,j.b); } for(int i=1;i<=Q;i++)printf("%d\n",ans[i]); }
- 1
信息
- ID
- 72
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 6
- 已通过
- 1
- 上传者