模拟赛-20190114-新魔法(distance)

2 篇文章 0 订阅

前言

第一篇模拟赛题思路总结

题目相关

题目链接

题目大意

给定一个长度为 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,y200000

题解

暴力分块…
按照出现次数进行分块
我们来列举一下要维护的信息:
颜色数组
对于所有颜色都维护出现位置的有序数组(我们发现输入后处理这个信息复杂度是 Θ ( 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;
}

总结

分块好题,很妙的思路

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值