「LG5397-天降之物」题解
P5397 [Ynoi2018] 天降之物
sol
基本部分
考虑根号分治。令阈值为 \(B\)。
对于每一种数,将其位置信息分为两部分存储:主体部分(\(siz>B\))与附加部分(\(siz\le B\))。
主体部分无需额外维护,附加部分用动态数组存下其所有位置。
令出现次数 \(>B\) 也就是有主体部分的数为大数,其余数为小数。
由于大数个数 \(\le \frac{n}{B}\),因此我们可以存下每一个大数的主体部分对于其余每一个数的答案。
以上是信息维护,下面讲解具体的修改与查询方式。
查询
首先,假如说存在大数,那么就可以利用存储的信息 \(O(1)\) 得到大数的主体部分与另一个数的答案。
那么事实上我们只需要考虑两个数的附加部分的贡献就行,双指针 \(O(B)\) 做到。
单次查询复杂度 \(O(B)\)。
修改
我们可以通过简单的技巧交换操作的 \(x,y\),使得 \(x\) 大小小于 \(y\)。
首先我们把原序列中所有 \(a=x\) 的位置都赋值为 \(y\)。对于附加部分,是 \(O(B)\) 的。对于主体部分,假如说存在主体部分,那么 \(x,y\) 的大小至少为 \(B\),这样的操作不超过 \(\frac{n}{B}\) 次,因此我们可以考虑每次暴力遍历整个数组修改,复杂度为 \(O(\frac{n^2}{B})\)。
然后用所有大数对 \(x\) 的答案更新其对 \(y\) 的答案,至多 \(\frac{n}{B}\) 个大数,直接遍历即可。
若 \(x\) 为大数或者合并后 \(y\) 的附加部分大小超过 \(B\),那么直接 \(O(n)\) 重构 \(y\) 对其它数的 \(ans\) 信息并清空附加部分。前者出现次数不超过 \(\frac{n}{B}\),对于后者只讨论 \(x\) 为小数的情况,显然出现次数也不超过 \(\frac{n}{B}\)。复杂度为 \(O(\frac{n^2}{B})\)。
细节
我们可以通过储存每一个数的实际对应编号以方便交换两数。
\(B\) 可以偏大于 \(\sqrt n\),因为大数复杂度更高一些。
code
const int N=1e5+5,B=500,M=N/B+5;
int n,m;
int a[N];
int mp[N];
vec<int> p[N];
int id[N],idx;
int ans[M][N];
inline void rebuild(int x){
if(!id[x])id[x]=++idx;
memset(ans[id[x]],0x3f,sizeof ans[id[x]]);
ans[id[x]][x]=0;
int d=inf;
rep(i,1,n)
if(a[i]==x)d=0;
else chmin(ans[id[x]][a[i]],++d);
d=inf;
per(i,n,1)
if(a[i]==x)d=0;
else chmin(ans[id[x]][a[i]],++d);
p[x].clear();
}
inline vec<int> merge(vec<int> &a,vec<int> &b){
vec<int> c(a.size()+b.size());
merge(a.begin(),a.end(),b.begin(),b.end(),c.begin());
return c;
}
inline void modify(int &x,int &y){
if(x==y||!x)return;
if(!y)return swap(x,y);
if(id[x])swap(x,y);
rep(i,1,idx)chmin(ans[i][y],ans[i][x]);
if(id[x]){
rep(i,1,n)if(a[i]==x)a[i]=y;
rebuild(y);
}else{
for(auto i:p[x])a[i]=y;
p[y]=merge(p[x],p[y]);
if(p[y].size()>B)rebuild(y);
}
p[x].clear();x=0;
}
inline int query(int &x,int &y){
if(!x||!y)return -1;
if(x==y)return 0;
int res=inf;
vec<int> tp=merge(p[x],p[y]);
repl(i,1,tp.size())if(a[tp[i-1]]^a[tp[i]])chmin(res,tp[i]-tp[i-1]);
if(id[x])chmin(res,ans[id[x]][y]);
if(id[y])chmin(res,ans[id[y]][x]);
return res;
}
int main(){
read(n),read(m);
rep(i,1,n)read(a[i]),p[a[i]].pub(i),mp[a[i]]=a[i];
rep(i,1,n)if(p[a[i]].size()>B)rebuild(a[i]);
int lst=0;
rep(i,1,m){
int o=read(),x=read()^lst,y=read()^lst;
if(o==1)modify(mp[x],mp[y]);
else{
lst=query(mp[x],mp[y]);
if(~lst)write(lst,'\n');
else writes("Ikaros\n"),lst=0;
}
}
return 0;
}

浙公网安备 33010602011771号