暴力。。。严格的说是mlogn+m√nlogn的。。。就是莫队+BIT。
然后我们可以按照值域分块,这样修改O(1)查询O(√n),这样总复杂度就是2*m*√n。
有点像做了一个时间复杂度的权衡。。。看起来查询变慢了,事实上总复杂度是变快了。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100050 #define maxm 1000050 using namespace std; int n,m,len=300,blo[maxn],st[maxn],ret=0,val[maxn],cnt[maxn],a[maxn],ans[maxm],p1,p2; int a1,a2,a3,a4; struct query { int l,r,a,b,id; query (int l,int r,int a,int b,int id):l(l),r(r),a(a),b(b),id(id) {} query () {} }q[maxm]; int read() { char ch;int data=0; while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9') { data=data*10+ch-'0'; ch=getchar(); } return data; } bool cmp(query x,query y) { if (blo[x.l]==blo[y.l]) return x.r<y.r; return blo[x.l]<blo[y.l]; } void build() { ret=1; for (int i=1;i<=n;i++) { blo[i]=ret; if (!(i%len)) {st[ret]=i;if (i!=n) ret++;} } if (n%len) st[ret]=n; } void modify(int x,int y) { bool flag=cnt[x]; cnt[x]+=y; if ((!cnt[x]) && (flag)) val[blo[x]]--; if ((cnt[x]) && (!flag)) val[blo[x]]++; } int ask(int l,int r) { int ret1=0,ret2=0; for (int i=1;i<=blo[l-1]-1;i++) ret1+=val[i]; for (int i=st[blo[l-1]-1]+1;i<=l-1;i++) ret1+=(cnt[i]>0); for (int i=1;i<=blo[r]-1;i++) ret2+=val[i]; for (int i=st[blo[r]-1]+1;i<=r;i++) ret2+=(cnt[i]>0); return ret2-ret1; } int main() { n=read();m=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=m;i++) { scanf("%d%d%d%d",&a1,&a2,&a3,&a4); q[i]=query(a1,a2,a3,a4,i); } build(); sort(q+1,q+m+1,cmp); for (int i=1;i<=m;i++) { for (;p1>q[i].l;p1--) modify(a[p1-1],1); for (;p1<q[i].l;p1++) modify(a[p1],-1); for (;p2>q[i].r;p2--) modify(a[p2],-1); for (;p2<q[i].r;p2++) modify(a[p2+1],1); ans[q[i].id]=ask(q[i].a,q[i].b); } for (int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }