[ AHOI 2013 ] 做業 & [ BZOJ 3809 ] Gty的二逼妹子序列

\(\\\)php

Description


給出一個長爲 \(n\) 的數列 \(A\)\(k\),屢次詢問:ios

對於一個區間 \([L_i,R_i]\),問區間內有多少個數在 \([a_i,b_i]\) 內,以及這些數共有多少個不一樣的值。c++

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

By wangyisong1996增強數據git

\(\\\)數組

Solution


看到最後一行心都涼了......優化

真的佩服鬆鬆鬆的速度 不知道比我高到哪裏去了spa

卡常卡到想吐(見代碼部分吧)`code

\(\\\)blog

首先確定莫隊,而後考慮第一問。排序

直接離散化以後權值樹狀數組,每次新加進來一個就在對應權值處 \(+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;
}
相關文章
相關標籤/搜索