题解: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;
}
posted @ 2026-04-17 06:37  Redolent  阅读(3)  评论(0)    收藏  举报