https://www.lydsy.com/JudgeOnline/problem.php?id=3236
第一种做法:
建两棵主席树分别处理两个问题。
第一个问题水,第二个问题参考SPOJ3267/DQUERY:D-query
但是代码量巨大,显然不能写。
第二种做法:
参考:https://blog.csdn.net/clover_hxy/article/details/56288794
对询问离线莫队,然后莫队里面套值域分块。
……值域分块还是很好写的就不讲了。
可以看出代码量巨短。
(emmm果然数据结构学傻了想的第一种做法敲了十分钟果断弃了查题解。)
(莫队还是太菜了要多练。)
#include<stack> #include<queue> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=1e5+5; const int M=1e6+5; inline int read(){int x=0,w=1;char ch=0;while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*w; } struct data{int pos,l,r,a,b; }q[M]; int a[N],cnt[N],ans[M][2],v[N],num[N],s,n,m; inline int bel(int x){return (x-1)/s+1;} inline bool cmp(data a,data b){return bel(a.l)==bel(b.l)?a.r<b.r:a.l<b.l; } inline void add(int k){if(!cnt[k])v[bel(k)]++;cnt[k]++;num[bel(k)]++; } inline void del(int k){cnt[k]--;num[bel(k)]--;if(!cnt[k])v[bel(k)]--; } void query(int pos,int l,int r){if(bel(l)==bel(r)){for(int i=l;i<=r;i++){if(cnt[i])ans[pos][1]++,ans[pos][0]+=cnt[i];}return;}for(int i=l;i<=bel(l)*s;i++)if(cnt[i])ans[pos][1]++,ans[pos][0]+=cnt[i];for(int i=(bel(r)-1)*s+1;i<=r;i++)if(cnt[i])ans[pos][1]++,ans[pos][0]+=cnt[i];for(int i=bel(l)+1;i<=bel(r)-1;i++)ans[pos][1]+=v[i],ans[pos][0]+=num[i]; } int main(){n=read(),m=read();s=sqrt(n);for(int i=1;i<=n;i++)a[i]=read();for(int i=1;i<=m;i++){q[i].pos=i,q[i].l=read(),q[i].r=read();q[i].a=read(),q[i].b=read();}sort(q+1,q+m+1,cmp);int ql=1,qr=0;for(int i=1;i<=m;i++){while(ql<q[i].l)del(a[ql++]);while(ql>q[i].l)add(a[--ql]);while(qr<q[i].r)add(a[++qr]);while(qr>q[i].r)del(a[qr--]);query(q[i].pos,q[i].a,q[i].b);}for(int i=1;i<=m;i++){printf("%d %d\n",ans[i][0],ans[i][1]);}return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++