前言
第一篇模拟赛题思路总结
题目相关
题目链接
题目大意
给定一个长度为
n
n
n序列,每一个位置
i
i
i都有一种颜色
a
i
a_i
ai
现在有
m
m
m次操作,操作分两种:
第一种操作,将所有颜色
x
x
x都替换成
y
y
y
第二种操作,询问所有满足两个点的颜色分别为
x
x
x和
y
y
y的点对的最小距离值
强制在线
数据范围
n , m , a i , x , y ≤ 200000 n,m,a_i,x,y\le200000 n,m,ai,x,y≤200000
题解
暴力分块…
按照出现次数进行分块
我们来列举一下要维护的信息:
颜色数组
对于所有颜色都维护出现位置的有序数组(我们发现输入后处理这个信息复杂度是
Θ
(
n
)
\Theta(n)
Θ(n)的,可以使用vector)
对于出现次数
≥
n
\ge\sqrt n
≥n的颜色,额外维护其到其它所有颜色的答案(输入后直接把整个序列扫一遍即可,我们发现满足条件的颜色只有
Θ
(
n
)
\Theta(\sqrt n)
Θ(n)种,总复杂度
Θ
(
n
n
)
\Theta(n\sqrt n)
Θ(nn),空间复杂度同)。为了方便表示,设ans[i][j]代表当前
i
i
i颜色是L颜色,其与
j
j
j颜色的答案
为了方便描述,我们称出现次数
≥
n
\ge\sqrt n
≥n的颜色为L颜色,称出现次数
≤
n
\le\sqrt n
≤n的颜色为S颜色
第一种操作
- L颜色&L颜色
归并维护有序数组,我们发现这种情况最多进行 n \sqrt n n次,所以这部分的复杂度为 Θ ( n n ) \Theta(n\sqrt n) Θ(nn)
Θ ( n ) \Theta(n) Θ(n)维护颜色数组,总复杂度 Θ ( n n ) \Theta(n\sqrt n) Θ(nn)
到其它所有颜色的答案也 Θ ( n ) \Theta(n) Θ(n)维护,总复杂度 Θ ( n n ) \Theta(n\sqrt n) Θ(nn) - S颜色&S颜色(注意,合并完后如果出现次数大于
n
\sqrt n
n,需要将S颜色转化成L颜色,容易发现这里最多出现
n
\sqrt n
n次,所以总复杂度
Θ
(
n
n
)
\Theta(n\sqrt n)
Θ(nn))
归并维护有序数组,复杂度 Θ ( n ) \Theta(\sqrt n) Θ(n),总复杂度为 Θ ( m n ) \Theta(m\sqrt n) Θ(mn)
Θ ( n ) \Theta(\sqrt n) Θ(n)暴力维护颜色数组,总复杂度 Θ ( m n ) \Theta(m\sqrt n) Θ(mn) - S颜色&L颜色
S颜色并入L颜色与L颜色并入S颜色的本质是一样的,唯一不同的在于L颜色并入S颜色后颜色数组中需要更新的数据不同
我们发现,L颜色 x x x并入S颜色 y y y,可以反向并入(即 y y y并入 x x x),并重新记下编号
我们发现答案数组并不好维护,所以我们可以开一个缓冲区,记录后面加入的零散的该颜色的位置(若缓冲区大小大于等于 n \sqrt n n就直接用缓冲区更新,复杂度是 Θ ( n n ) \Theta(n\sqrt n) Θ(nn)的)
更新缓冲区数组的复杂度是 Θ ( m n ) \Theta(m\sqrt n) Θ(mn)的
注意:任意颜色合并完毕后需要更新 n \sqrt n n个L颜色中对应的值
第二种操作
- L颜色&L颜色
我们发现,答案数组维护的是L颜色的非缓冲区内位置与别的颜色之间的答案,那么我们也就只需要将min(ans[x][y],ans[y][x])的值min上缓冲区之间的答案,复杂度 Θ ( n ) \Theta(\sqrt n) Θ(n) - L颜色&S颜色
将ans[x][y]min上缓冲区的答案,复杂度 Θ ( n ) \Theta(\sqrt n) Θ(n) - S颜色&S颜色
一次归并即可
代码
贴上AC代码
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cmath>
namespace fast_IO
{
const int IN_LEN=10000000,OUT_LEN=10000000;
char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;
inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}
inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}
inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
}
using namespace fast_IO;
#define getchar() getchar_()
#define putchar(x) putchar_((x))
#define rg register
typedef long long LL;
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;}
template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline void swap(T&a,T&b){T c=a;a=b;b=c;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline T lcm(const T a,const T b){return a/gcd(a,b)*b;}
template <typename T> inline T square(const T x){return x*x;};
template <typename T> inline void read(T&x)
{
char cu=getchar();x=0;bool fla=0;
while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}
while(isdigit(cu))x=x*10+cu-'0',cu=getchar();
if(fla)x=-x;
}
template <typename T> inline void printe(const T x)
{
if(x>=10)printe(x/10);
putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{
if(x<0)putchar('-'),printe(-x);
else printe(x);
}
const int INF=998244353;
unsigned int PART;
int n,m,col[200001];
int lsh[200001],tot,lastans;
std::vector<int>p[200001],h[200001],ans[200001];
std::vector<int>::iterator Posu,Posv;
void add(std::vector<int>&w,std::vector<int>&v)
{
std::vector<int>u;u.clear();
for(unsigned int i=0;i<w.size();i++)u.push_back(w[i]);
w.clear();
Posu=u.begin(),Posv=v.begin();
while(Posu!=u.end()&&Posv!=v.end())
if((*Posu)<(*Posv))w.push_back(*Posu),Posu++;
else w.push_back(*Posv),Posv++;
while(Posu!=u.end())w.push_back(*Posu),Posu++;
while(Posv!=v.end())w.push_back(*Posv),Posv++;
v.clear();
}
int calc(std::vector<int>&u,std::vector<int>&v)
{
int ans=INF,lasu=-INF,lasv=-INF;
Posu=u.begin(),Posv=v.begin();
while(Posu!=u.end()&&Posv!=v.end())
if((*Posu)<(*Posv))lasu=*Posu,Posu++,mind(ans,lasu-lasv);
else lasv=*Posv,Posv++,mind(ans,lasv-lasu);
while(Posu!=u.end())lasu=*Posu,Posu++,mind(ans,lasu-lasv);
while(Posv!=v.end())lasv=*Posv,Posv++,mind(ans,lasv-lasu);
return ans;
}
int bak[200001];
bool isL[200001];
void L_color_update(const int u)
{
std::vector<int>*U=&ans[u];
for(rg int i=1;i<=tot;i++)(*U)[i]=INF;
int close=INF;
for(rg int i=1;i<=n;i++,close++)
if(col[i]==u)close=0;
else mind((*U)[col[i]],close);
close=INF;
for(rg int i=n;i>=1;i--,close++)
if(col[i]==u)close=0;
else mind((*U)[col[i]],close);
}
bool is[200001];
void upd(std::vector<int>&u)
{
for(Posu=u.begin();Posu!=u.end();Posu++)is[*Posu]=1;
u.clear();
}
int Lstack[200001],Ltop;
void push(const int x){Lstack[++Ltop]=x,ans[x].resize(200001),isL[x]=1;}
void pop(const int x)
{
ans[x].clear(),isL[x]=0;
for(rg int i=1;i<=Ltop;i++)
if(Lstack[i]==x)
{
Ltop--;
for(rg int j=i;j<=Ltop;j++)Lstack[j]=Lstack[j+1];
return;
}
}
int main()
{
read(n),read(m),PART=sqrt(n);
for(rg int i=1;i<=n;i++)
{
read(col[i]);
if(!lsh[col[i]])lsh[col[i]]=++tot;
col[i]=lsh[col[i]];
p[col[i]].push_back(i);
}
for(rg int i=1;i<=tot;i++)
if(p[i].size()>=PART)
{
push(i);
L_color_update(i);
}
for(rg int i=1;i<=m;i++)
{
int opt,x,y;read(opt),read(x),read(y);x^=lastans,y^=lastans;
if(opt==1)
{
const int X=lsh[x],Y=lsh[y];
if(!X||x==y)continue;
if(!Y)
{
lsh[x]=0;
lsh[y]=X;
continue;
}
if(isL[X])
{
if(isL[Y])
{
upd(p[X]),upd(p[Y]),upd(h[X]),upd(h[Y]);
for(rg int j=1;j<=n;j++)if(is[j])p[Y].push_back(j),is[j]=0,col[j]=Y;
L_color_update(Y);
lsh[x]=0,pop(X);
for(rg int j=1;j<=Ltop;j++)
{
const int v=Lstack[j];
ans[v][Y]=ans[Y][v];
}
}
else
{
for(Posv=p[Y].begin();Posv!=p[Y].end();Posv++)col[*Posv]=X;
add(h[X],p[Y]);
for(rg int j=1;j<=Ltop;j++)
{
const int v=Lstack[j];
mind(ans[v][X],ans[v][Y]),ans[v][Y]=INF;
}
if(h[X].size()>=PART)
{
upd(p[X]),upd(h[X]);
for(rg int j=1;j<=n;j++)if(is[j])p[X].push_back(j),is[j]=0;
L_color_update(X);
}
lsh[x]=0,lsh[y]=X;
}
}
else
{
if(isL[Y])
{
for(Posv=p[X].begin();Posv!=p[X].end();Posv++)col[*Posv]=Y;
add(h[Y],p[X]);
for(rg int j=1;j<=Ltop;j++)
{
const int v=Lstack[j];
mind(ans[v][Y],ans[v][X]),ans[v][X]=INF;
}
if(h[Y].size()>=PART)
{
upd(p[Y]),upd(h[Y]);
for(rg int j=1;j<=n;j++)if(is[j])p[Y].push_back(j),is[j]=0;
L_color_update(Y);
}
lsh[x]=0;
}
else
{
for(Posv=p[X].begin();Posv!=p[X].end();Posv++)col[*Posv]=Y;
add(p[Y],p[X]);
for(rg int j=1;j<=Ltop;j++)
{
const int v=Lstack[j];
mind(ans[v][Y],ans[v][X]),ans[v][X]=INF;
}
if(p[Y].size()>=PART)
{
push(Y);
upd(p[Y]);
for(rg int j=1;j<=n;j++)if(is[j])p[Y].push_back(j),is[j]=0;
L_color_update(Y);
for(rg int j=1;j<=Ltop;j++)
{
const int v=Lstack[j];
ans[v][Y]=ans[Y][v];
}
}
lsh[x]=0;
}
}
}
else
{
if(!lsh[x]||!lsh[y])putchar('y'),putchar('y'),putchar('b'),putchar(' '),putchar('i'),putchar('s'),putchar(' '),putchar('o'),putchar('u'),putchar('r'),putchar(' '),putchar('r'),putchar('e'),putchar('d'),putchar(' '),putchar('s'),putchar('u'),putchar('n'),putchar(' '),putchar('a'),putchar('n'),putchar('d'),putchar(' '),putchar('z'),putchar('s'),putchar('y'),putchar(' '),putchar('i'),putchar('s'),putchar(' '),putchar('o'),putchar('u'),putchar('r'),putchar(' '),putchar('b'),putchar('l'),putchar('u'),putchar('e'),putchar(' '),putchar('m'),putchar('o'),putchar('o'),putchar('n'),lastans=0;
else
{
const int X=lsh[x],Y=lsh[y];
if(isL[X])
{
if(isL[Y])print(lastans=min(min(ans[X][Y],ans[Y][X]),calc(h[X],h[Y])));
else print(lastans=min(ans[X][Y],calc(h[X],p[Y])));
}
else
{
if(isL[Y])print(lastans=min(ans[Y][X],calc(p[X],h[Y])));
else print(lastans=calc(p[X],p[Y]));
}
}
putchar('\n');
}
}
return flush(),0;
}
总结
分块好题,很妙的思路