[ Luogu 3709 ] 大爺的字符串題

\(\\\)ios

Description


原題題面太過混亂出題人語文涼涼c++

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

對於一個區間 \([L_i,R_i]\),把區間內的全部數最少劃分紅多少個數集,使得每個集合內沒有相同元素。spa

  • \(A_i\le 10^9,n,m\le 2\times 10^5\)

\(\\\)code

Solution


題目的模型很容易轉化成區間衆數問題。ip

莫隊求解區間衆數。get

首先數據範圍是假的,離散化以後就開的下桶了。string

對於區間擴張,確定是加一下桶,而後跟當前答案取 \(max\)it

問題在於區間縮小時,刪除一個數怎麼搞。io

\(\\\)

開始有一個 too simple 想法,是用堆去維護當前答案區間內全部數出現個數,而後懶惰刪除法,每次更新時判斷一下堆頂是否正確。

想想是對的,可是 \(O(N\sqrt NlogN)\) 的複雜度對於 \(2\times 10^5\) 很吃力。

\(\\\)

一個機智的作法。

\(cnt[i]\) 表示 \(bkt[x]=i\) 的個數,也就是當前區間裏出現次數爲 \(i\) 的數的個數。

空間沒有問題,由於最多出現數列長度的次數。

這樣一來修改就容易了不少,減的時候只須要判斷一下,當前數對應的 \(cnt\) 是否 \(>1\) 便可。

注意加減是對 \(cnt\)\(bkt\) 的同時更新。

\(\\\)

Code


#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 200000
#define R 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;
}

int n,m,ans,bl[N],cnt[N],bkt[N],s[N],tmp[N];

struct Q{int l,r,ans,id;}q[N];

inline bool cmp1(Q x,Q y){
  return bl[x.l]==bl[y.l]?x.r<y.r:bl[x.l]<bl[y.l];
}

inline bool cmp2(Q x,Q y){return x.id<y.id;}

inline void add(int p){
  --cnt[bkt[s[p]]];
  ++cnt[++bkt[s[p]]];
  ans=max(ans,bkt[s[p]]);
}

inline void del(int p){
  --cnt[bkt[s[p]]];
  if(ans==bkt[s[p]]&&!cnt[bkt[s[p]]]) --ans;
  ++cnt[--bkt[s[p]]];
}

int main(){
  n=rd(); m=rd();
  int t=sqrt(n),tot=0;
  for(R int i=1,cntt=1;i<=n;++i){
    tmp[i]=s[i]=rd();
    if(i%t==0) ++cntt;
    bl[i]=cntt;
  }
  sort(tmp+1,tmp+1+n);
  for(R int i=1;i<=n;++i){
    tmp[++tot]=tmp[i];
    while(tmp[i+1]==tmp[i]&&i<=n) ++i;
  }
  for(R int i=1;i<=n;++i) s[i]=lower_bound(tmp+1,tmp+1+tot,s[i])-tmp;
  for(R int i=1;i<=m;++i){
    q[i].l=rd(); q[i].r=rd(); q[i].id=i;
  }
  sort(q+1,q+1+m,cmp1);
  bkt[s[1]]=cnt[1]=ans=1;
  int nowl=1,nowr=1;
  for(R int i=1;i<=m;++i){
    while(nowl<q[i].l){del(nowl);++nowl;}
    while(nowl>q[i].l){--nowl;add(nowl);}
    while(nowr>q[i].r){del(nowr);--nowr;}
    while(nowr<q[i].r){++nowr;add(nowr);}
    q[i].ans=ans;
  }
  sort(q+1,q+1+m,cmp2);
  for(R int i=1;i<=m;++i) printf("%d\n",-q[i].ans);
  return 0;
}
相關文章
相關標籤/搜索