LOJ.6284.數列分塊入門8(分塊)
阿新 • • 發佈:2018-02-20
統計 完整 入門 source inline set min 一個數 tdi
換句話說,要想讓一個操作耗費O(n)的時間,要先花費sqrt(n)個操作修改數列
----by hzwer
題目鏈接
\(Description\)
給出一個長為n的數列,以及n個操作,操作涉及區間詢問等於一個數c的元素,並將這個區間的所有元素改為c。
\(Solution\)
模擬一些數據可以發現,詢問後一整段都會被修改,幾次詢問後數列可能只剩下幾段不同的區間了。
那麽還是暴力,每個塊維護的是整個塊是否僅被一種權值覆蓋。查詢時對於相同權值的塊就可以O(1)統計;否則暴力統計並修改答案;不完整的塊暴力。
這樣看似最差情況下每次需要O(n)的時間,但實際遠遠到不了
假設初始序列都是同一個值,那麽查詢需要O(sqrt(n)),如果這時進行區間修改,那麽最多會破壞首尾兩個塊的標記
所以只能使後面的詢問至多多2個塊的暴力時間,所以均攤每次操作復雜度為O(sqrt(n))
----by hzwer
#include <cmath>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=1e5+5,MAXIN=1e6;
int n,size,sizen,A[N],tag[2000],bel[N],L[2000 ],R[2000];
bool cover[2000];
char IN[MAXIN],*SS=IN,*TT=IN;
inline int read()
{
int now=0,f=1;register char c=gc();
for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now*f;
}
int Count(int l,int r,int v)
{
int res=0;
for(int i=l; i<=r; ++i)
if (A[i]==v) ++res; else A[i]=v;
return res;
}
void Reset(int p,int l,int r,int vbef,int v)
{//Reset [L(p),l)&&(r,R(p)] to vbef,[l,r] to v
for(int i=L[p]; i<l; ++i) A[i]=vbef;
for(int i=l; i<=r; ++i) A[i]=v;
int t=std::min(n,R[p]);
for(int i=r+1; i<=t; ++i) A[i]=vbef;
cover[p]=0;
}
int Get_scatter(int l,int r,int v)
{
if(cover[bel[l]])
if(tag[bel[l]]==v) return r-l+1;
else Reset(bel[l],l,r,tag[bel[l]],v);
else return Count(l,r,v);
return 0;
}
int Query(int l,int r,int v)
{
int res=Get_scatter(l,std::min(r,R[bel[l]]),v);
if(bel[l]!=bel[r]) res+=Get_scatter(L[bel[r]],r,v);
for(int i=bel[l]+1; i<bel[r]; ++i)
if(cover[i])
if(tag[i]==v) res+=bel[l]==bel[n]?sizen:size;
else tag[i]=v;
else
res+=Count(L[i],R[i],v), cover[i]=1, tag[i]=v;
return res;
}
int main()
{
n=read(), size=sqrt(n);
for(int i=1; i<=n; ++i) bel[i]=(i-1)/size+1, A[i]=read();
for(int i=1; i<=bel[n]; ++i) L[i]=(i-1)*size+1,R[i]=i*size;
sizen=n-(bel[n]-1)*size;
for(int l,r,c,i=1; i<=n; ++i)
l=read(), r=read(), c=read(), printf("%d\n",Query(l,r,c));
return 0;
}
LOJ.6284.數列分塊入門8(分塊)