题解:P15599 [ICPC 2020 Jakarta R] Token Distance
太深刻了。
题意
给定一个序列 \(a\),支持单点修改,区间查询重排后是否能构成等差数列。
思路
首先如果能构成等差数列,公差一定为 \(\frac{\max-\min}{r-l}\)。然后还有一个表示方法:相邻两数的差的 \(\gcd\)。下面证明这个是对的:
设相邻两数的差的 \(\gcd\) 为 \(x\),公差为 \(d\),显然有 \(d|x\)。将所有数同时减去最小值,再除以 \(d\) 可以得到一个 \([0,n-1]\) 的排列。那么相当于这样一个排列相邻两数的差被 \(\frac{x}{d}\) 整除。然后因为这个排列存在 \(0\),所以每个数都是 \(\frac{x}{d}\) 的倍数,得到 \(x=d\)。
但是这个条件是必要不充分的。还得加上区间内不存在相同的数。我们考虑区间数颜色,维护每个数上一次出现的位置 \(pre_i\),区间颜色数为 \(\sum[pre_i<l]\)。区间没有重复颜色就等价于 \(\max pre_i<l\)。于是拿 set 动态维护前驱,拿线段树维护区间 \(\max,\min,\gcd\) 即可。
注意要把 \(d=0\) 的情况特判掉。
bonus
这个做法还能做区间修改。
代码
#include <bits/stdc++.h>
using namespace std;
constexpr int N=1e5+5;
int n,m,a[N],pre[N];
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
struct SegmentTree1{
int s[N<<2];
void pushup(int p){s[p]=__gcd(s[ls(p)],s[rs(p)]);}
void build(int p,int pl,int pr){
if(pl==pr){s[p]=abs(a[pl]-a[pl-1]);return;}
const int mid=pl+pr>>1;
build(ls(p),pl,mid),build(rs(p),mid+1,pr);
pushup(p);
}
void update(int p,int pos,int x,int pl,int pr){
if(pl==pr){s[p]=x;return;}
const int mid=pl+pr>>1;
if(mid>=pos)update(ls(p),pos,x,pl,mid);
else update(rs(p),pos,x,mid+1,pr);
pushup(p);
}
int query(int p,int l,int r,int pl,int pr){
if(l<=pl&&pr<=r)return s[p];
const int mid=pl+pr>>1;
if(mid>=r)return query(ls(p),l,r,pl,mid);
if(mid<l)return query(rs(p),l,r,mid+1,pr);
return __gcd(query(ls(p),l,r,pl,mid),query(rs(p),l,r,mid+1,pr));
}
}t1;
struct SegmentTree2{
int mx[N<<2],mn[N<<2];
void pushup(int p){mx[p]=max(mx[ls(p)],mx[rs(p)]),mn[p]=min(mn[ls(p)],mn[rs(p)]);}
void build(int p,int pl,int pr){
if(pl==pr){mx[p]=mn[p]=a[pl];return;}
const int mid=pl+pr>>1;
build(ls(p),pl,mid),build(rs(p),mid+1,pr);
pushup(p);
}
void update(int p,int pos,int x,int pl,int pr){
if(pl==pr){mx[p]=mn[p]=x;return;}
const int mid=pl+pr>>1;
if(mid>=pos)update(ls(p),pos,x,pl,mid);
else update(rs(p),pos,x,mid+1,pr);
pushup(p);
}
pair<int,int>query(int p,int l,int r,int pl,int pr){
if(l<=pl&&pr<=r)return {mx[p],mn[p]};
const int mid=pl+pr>>1;
if(mid>=r)return query(ls(p),l,r,pl,mid);
if(mid<l)return query(rs(p),l,r,mid+1,pr);
pair<int,int>res1=query(ls(p),l,r,pl,mid);
pair<int,int>res2=query(rs(p),l,r,mid+1,pr);
return {max(res1.first,res2.first),min(res1.second,res2.second)};
}
}t2;
struct SegmentTree3{
int mx[N<<2];
void pushup(int p){mx[p]=max(mx[ls(p)],mx[rs(p)]);}
void build(int p,int pl,int pr){
if(pl==pr){mx[p]=pre[pl];return;}
const int mid=pl+pr>>1;
build(ls(p),pl,mid),build(rs(p),mid+1,pr);
pushup(p);
}
void update(int p,int pos,int x,int pl,int pr){
if(pl==pr){mx[p]=x;return;}
const int mid=pl+pr>>1;
if(mid>=pos)update(ls(p),pos,x,pl,mid);
else update(rs(p),pos,x,mid+1,pr);
pushup(p);
}
int query(int p,int l,int r,int pl,int pr){
if(l<=pl&&pr<=r)return mx[p];
const int mid=pl+pr>>1;
if(mid>=r)return query(ls(p),l,r,pl,mid);
if(mid<l)return query(rs(p),l,r,mid+1,pr);
return max(query(ls(p),l,r,pl,mid),query(rs(p),l,r,mid+1,pr));
}
}t3;
int cnt=0;
map<int,int>mp,lst;
set<int>s[N<<1];
signed main(){
clock_t _st=clock();
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)if(mp.find(a[i])==mp.end())mp[a[i]]=++cnt;
for(int i=1;i<=n;i++)pre[i]=lst[a[i]],lst[a[i]]=i,s[mp[a[i]]].insert(i);
t1.build(1,1,n),t2.build(1,1,n),t3.build(1,1,n);
for(int i=1;i<=m;i++){
int op,x,y;cin>>op>>x>>y;
if(op==1){
if(mp.find(y)==mp.end())mp[y]=++cnt;
t2.update(1,x,y,1,n);
t1.update(1,x,abs(y-a[x-1]),1,n);
if(x!=n)t1.update(1,x+1,abs(a[x+1]-y),1,n);
int val=mp[a[x]];
auto it=s[val].erase(s[val].find(x));
if(it!=s[val].end())t3.update(1,*it,pre[*it]=pre[x],1,n);
it=s[val=mp[a[x]=y]].insert(x).first;
t3.update(1,x,pre[x]=(it!=s[val].begin()?*prev(it):0),1,n);
if(next(it)!=s[val].end())t3.update(1,*next(it),pre[*next(it)]=x,1,n);
}else{
pair<int,int>res=t2.query(1,x,y,1,n);
if(res.first==res.second||(t3.query(1,x,y,1,n)<x&&(res.first-res.second)==1ll*(y-x)*t1.query(1,x+1,y,1,n)))cout<<"Yes\n";
else cout<<"No\n";
}
}
clock_t _ed=clock();
cerr<<(_ed-_st)*1.0/CLOCKS_PER_SEC<<'\n';
return 0;
}

浙公网安备 33010602011771号