[ AHOI 2013 ] 作业 & [ BZOJ 3809 ] Gty的二逼妹子序列

\(\\\)

Description


给出一个长为 \(n\) 的数列 \(A\)\(k\),多次询问:

对于一个区间 \([L_i,R_i]\),问区间内有多少个数在 \([a_i,b_i]\) 内,以及这些数共有多少个不同的值。

  • \(n\le 10^5,m\le 10^6\)

By wangyisong1996加强数据

\(\\\)

Solution


看到最后一行心都凉了......

真的佩服松松松的速度 不知道比我高到哪里去了

卡常卡到想吐(见代码部分吧)`

\(\\\)

首先肯定莫队,然后考虑第一问。

直接离散化之后权值树状数组,每次新加进来一个就在对应权值处 \(+1\) ,删除 \(-1\)

对于第二问,我们无法确定当前区间里有多少个是个问题。

于是直接再开一个辅助桶,以及另一个询问用的权值树状数组。

加入时若以前没有(桶为空),则在这一权值处 \(+1\) ,删除时若桶清空成 \(0\) ,则在对应权值处 \(-1\)

回答就直接区间减法即可。

注意 lower_boundupper_bound 的时候可能越界,所以要加上哨兵。

\(\\\)

Code


还是说一下卡常用了点啥吧.....

  • BZOJ 专用的 int 优化

  • 读入 & 输出优化

  • 莫队对询问排序时的奇偶性讨论

  • 很迷的块的大小,实测 \(\frac{N}{\sqrt M}\) 最快

    关于这个粘一个洛谷日报上的证明

    我们设块长度为 \(S\) ,那么对于任意多个在同一块内的询问,挪动的距离就是 \(n\),一共\(\frac{n}{S}\) 个块,移动的总次数就是\(\frac{n^2}{S}\),移动可能跨越块,所以还要加上一个 \(mS\) 的复杂度,总复杂度为 \(O(\frac{n^2}{S}+mS)\) ,我们要让这个值尽量小,\(S\)\(\frac{n}{\sqrt{m}}\) 是最优的,此时复杂度为

    \[O(\frac{n^2}{\frac{n}{\sqrt{m}}}+m(\frac{n}{\sqrt{m}}))=O(n\sqrt{m}) \]

#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 100010
#define M 1000010
#define Rg register
#define gc getchar
using namespace std;
 
inline int rd(){
  int x=0; bool f=0; char c=gc();
  while(!isdigit(c)){if(c=='-')f=1;c=gc();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
  return f?-x:x;
}
 
inline void print(int x){
  Rg int y=10,len=1;
  while(x>=y){y=(y<<1)+(y<<3);++len;}
  while(len--){y/=10;putchar('0'+x/y);x%=y;}
}
 
int n,m,tot,ans,ans1[M],ans2[M],s[N],bl[N],cnt[N],tmp[N];
 
struct Q{int l,r,L,R,id;}q[M];
 
inline bool cmp(Q x,Q y){
  if(bl[x.l]!=bl[y.l]) return bl[x.l]<bl[y.l];
  return bl[x.l]&1?x.r<y.r:x.r<y.r;
}
 
struct BIT{
  int c[N];
  inline int lowbit(int x){return x&-x;}
  inline void add(int p,int x){
    for(;p<=n;p+=lowbit(p)) c[p]+=x;
  }
  inline int query(int p){
    int res=0;
    for(;p;p-=lowbit(p)) res+=c[p];
    return res;
  }
}bitcnt,bitsum;
 
inline void add(int p){
  ++cnt[s[p]];
  bitsum.add(s[p],1);
  if(cnt[s[p]]==1) bitcnt.add(s[p],1);
}
 
inline void del(int p){
  --cnt[s[p]];
  bitsum.add(s[p],-1);
  if(!cnt[s[p]]) bitcnt.add(s[p],-1);
}
 
int main(){
  n=rd(); m=rd();
  int t=n/sqrt(m);
  for(Rg int i=1;i<=n;++i){
    tmp[i]=s[i]=rd();
    bl[i]=i/t+1;
  }
  sort(tmp+1,tmp+1+n);
  for(Rg int i=1;i<=n;++i){
    tmp[++tot]=tmp[i];
    while(tmp[i+1]==tmp[i]) ++i;
  }
  tmp[++tot]=2000000000;
  for(Rg int i=1;i<=n;++i) s[i]=lower_bound(tmp+1,tmp+1+tot,s[i])-tmp;
  for(Rg int i=1;i<=m;++i){
    q[i].l=rd(); q[i].r=rd(); q[i].id=i;
    q[i].L=lower_bound(tmp+1,tmp+1+tot,rd())-tmp;
    q[i].R=upper_bound(tmp+1,tmp+1+tot,rd())-tmp-1;
  }
  sort(q+1,q+1+m,cmp);
  int l=1,r=1;
  cnt[s[1]]=1;
  bitcnt.add(s[1],1);
  bitsum.add(s[1],1);
  for(Rg int i=1;i<=m;++i){
    if(q[i].L>q[i].R){
      ans1[q[i].id]=ans2[q[i].id]=0;
      continue;
    }
    while(l<q[i].l){del(l);++l;}
    while(l>q[i].l){--l;add(l);}
    while(r>q[i].r){del(r);--r;}
    while(r<q[i].r){++r;add(r);}
    ans1[q[i].id]=bitsum.query(q[i].R)-bitsum.query(q[i].L-1);
    ans2[q[i].id]=bitcnt.query(q[i].R)-bitcnt.query(q[i].L-1);
  }
  for(Rg int i=1;i<=m;++i){
    print(ans1[i]); putchar(' ');
    print(ans2[i]); putchar('\n');
  }
  return 0;
}
posted @ 2018-11-21 15:41  SGCollin  阅读(...)  评论(...编辑  收藏