【数据结构】你能凑出一个等差数列吗?
一个静态问题
找一个最长的子区间使得加入至多
多解输出
考虑可以形成一个等差数列的条件:
-
中所有数模 同余。 -
极差不超过
。 -
没有重复数字
考虑扫描线,从右至左扫描左端点,对于极差这个东西,可以用线段树和单调栈维护最大最小值。
记录一个 “可用的右端点”
将
考虑极差不超过某个值,就是
时间复杂度
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5,M = 2e9;
typedef long long ll;
int n,k,d;
struct Seg_Tree{
ll a[N << 2],tag[N << 2];
inline void pushup(int pos) {a[pos] = max(a[pos << 1],a[pos << 1 | 1]);}
inline void pushdown(int pos)
{
a[pos << 1] += tag[pos];
a[pos << 1 | 1] += tag[pos];
tag[pos << 1] += tag[pos];
tag[pos << 1 | 1] += tag[pos];
tag[pos] = 0;
}
inline void build(int l,int r,int pos)
{
if(l == r) {a[pos] = 1ll * l * d + 1ll * k * d; return;}
int mid = (l + r) >> 1;
build(l,mid,pos << 1); build(mid + 1,r,pos << 1 | 1);
pushup(pos);
}
inline void modify(int l,int r,int L,int R,ll k,int pos)
{
if(L <= l && r <= R) {a[pos] += k; tag[pos] += k; return;}
int mid = (l + r) >> 1;
pushdown(pos);
if(L <= mid) modify(l,mid,L,R,k,pos << 1);
if(R > mid) modify(mid + 1,r,L,R,k,pos << 1 | 1);
pushup(pos);
}
inline int query(int l,int r,int L,int R,ll req,int pos)
{
if(!(L <= l && r <= R))
{
int mid = (l + r) >> 1;
pushdown(pos); pushup(pos);
int ret = 0;
if(L <= mid) ret = max(ret,query(l,mid,L,R,req,pos << 1));
if(R > mid) ret = max(ret,query(mid + 1,r,L,R,req,pos << 1 | 1));
return ret;
}
if(l == r) {return (a[pos] >= req) ? l : L;}
int mid = (l + r) >> 1;
pushdown(pos);
pushup(pos);
if(a[pos << 1 | 1] >= req) return query(mid + 1,r,L,R,req,pos << 1 | 1);
else return query(l,mid,L,R,req,pos << 1);
}
inline ll qval(int l,int r,int x,int pos)
{
if(l == r) return a[pos];
pushdown(pos); pushup(pos);
int mid = (l + r) >> 1;
if(x <= mid) return qval(l,mid,x,pos << 1);
else return qval(mid + 1,r,x,pos << 1 | 1);
}
}t;
int a[N];
inline void solve1()
{
int ansl = 1,ansr = 1;
for(int i = 1,j;i <= n;i++)
{
j = i;
while(j < n && a[j + 1] == a[i]) ++j;
if(j - i + 1 > ansr - ansl + 1) ansr = j,ansl = i;
}
cout<<ansl<<" "<<ansr;
}
struct Stack{
int s[N],top = 0;
inline int front() {return s[top];}
inline int scd() {return s[top - 1];}
inline void push(int x) {s[++top] = x;}
}mx,mn;
set <int> s;
int main()
{
cin>>n>>k>>d;
for(int i = 1;i <= n;i++) cin>>a[i],a[i] += 1e9;
if(!d) {solve1(); return 0;}
int ansl = n,ansr = n;
t.build(1,n,1); mx.s[0] = n + 1; mn.s[0] = n + 1;
for(int l = n,r = n,nr = n,mod = a[n] % d;l >= 1;l--)
{
int lst = l + 1;
while(mx.top > 0 && a[l] >= a[mx.front()])
{
t.modify(1,n,lst,mx.scd() - 1,a[mx.front()],1);
lst = mx.scd();
--mx.top;
}
mx.push(l);
t.modify(1,n,l,lst - 1,-a[l],1);
lst = l + 1;
while(mn.top > 0 && a[l] <= a[mn.front()])
{
t.modify(1,n,lst,mn.scd() - 1,-a[mn.front()],1);
lst = mn.scd();
--mn.top;
}
mn.push(l);
t.modify(1,n,l,lst - 1,a[l],1);
if(mod != a[l] % d) nr = l,s.clear(),mod = a[l] % d;
while(s.find(a[l]) != s.end()) s.erase(a[nr]),nr--;
s.insert(a[l]);
int ar = t.query(1,n,l,nr,1ll * l * d,1);
if(ar - l + 1 >= ansr - ansl + 1) ansr = ar,ansl = l;
}
cout<<ansl<<" "<<ansr;
return 0;
}
一个动态问题
给定长度为
1 x y
:将
2 l r k
:询问区间
强制在线。
再来考虑充要条件:
-
没有相同的数
-
极差为
我们发现,这个时候你不能再通过模
考虑其他的条件,发现任意两项的差都是
于是有了这条限制:
- 定义差分序列
, 。
我们发现,如果满足前两个条件,又满足第三个条件,那么这一定是一个等差数列,如果不满足第三个条件,就一定不是。
而且上文又提到等差数列一定满足条件
这样,对于相同的数,我们套路地维护
所以,外面用
时间复杂度
什么?你说 pushup 的时候暴力 gcd 复杂度
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5,inf = 2e9;
struct Segment_Tree{
int maxi[N << 2],mini[N << 2],g[N << 2],pre[N << 2];
inline void pushup1(int pos) {maxi[pos] = max(maxi[pos << 1],maxi[pos << 1 | 1]); mini[pos] = min(mini[pos << 1],mini[pos << 1 | 1]);}
inline void pushup2(int pos) {g[pos] = __gcd(g[pos << 1],g[pos << 1 | 1]);}
inline void pushup3(int pos) {pre[pos] = max(pre[pos << 1],pre[pos << 1 | 1]);}
inline void modify_num(int l,int r,int x,int k,int pos)
{
if(l == r) {maxi[pos] = mini[pos] = k; return;}
int mid = (l + r) >> 1;
if(x <= mid) modify_num(l,mid,x,k,pos << 1);
else modify_num(mid + 1,r,x,k,pos << 1 | 1);
pushup1(pos);
}
inline void modify_del(int l,int r,int x,int k,int pos)
{
if(l == r) {g[pos] = k; return;}
int mid = (l + r) >> 1;
if(x <= mid) modify_del(l,mid,x,k,pos << 1);
else modify_del(mid + 1,r,x,k,pos << 1 | 1);
pushup2(pos);
}
inline void modify_pre(int l,int r,int x,int k,int pos)
{
if(l == r) {pre[pos] = k; return;}
int mid = (l + r) >> 1;
if(x <= mid) modify_pre(l,mid,x,k,pos << 1);
else modify_pre(mid + 1,r,x,k,pos << 1 | 1);
pushup3(pos);
}
inline pair <int,int> query_num(int l,int r,int L,int R,int pos)
{
if(L <= l && r <= R) return make_pair(maxi[pos],mini[pos]);
int mid = (l + r) >> 1; pair <int,int> now,ret = make_pair(-inf,inf);
if(L <= mid) now = query_num(l,mid,L,R,pos << 1),ret.first = max(ret.first,now.first),ret.second = min(ret.second,now.second);
if(R > mid) now = query_num(mid + 1,r,L,R,pos << 1 | 1),ret.first = max(ret.first,now.first),ret.second = min(ret.second,now.second);
return ret;
}
inline int query_del(int l,int r,int L,int R,int pos)
{
if(L <= l && r <= R) return g[pos];
int mid = (l + r) >> 1,ret = 0;
if(L <= mid) ret = __gcd(ret,query_del(l,mid,L,R,pos << 1));
if(R > mid) ret = __gcd(ret,query_del(mid + 1,r,L,R,pos << 1 | 1));
return ret;
}
inline int query_pre(int l,int r,int L,int R,int pos)
{
if(L <= l && r <= R) return pre[pos];
int mid = (l + r) >> 1,ret = 0;
if(L <= mid) ret = max(ret,query_pre(l,mid,L,R,pos << 1));
if(R > mid) ret = max(ret,query_pre(mid + 1,r,L,R,pos << 1 | 1));
return ret;
}
}t;
map <int,int> mp;
set <int> s[N * 2];
int n,m,a[N],cnt = 0;
int main()
{
ios::sync_with_stdio(0); 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;
if(s[mp[a[i]]].size()) t.modify_pre(1,n,i,*s[mp[a[i]]].rbegin(),1);
s[mp[a[i]]].insert(i);
}
for(int i = 1;i <= n - 1;i++) t.modify_del(1,n,i,a[i] - a[i + 1],1);
for(int i = 1;i <= n;i++) t.modify_num(1,n,i,a[i],1);
for(int i = 1,op,x,y,k,yesnum = 0;i <= m;i++)
{
cin>>op>>x>>y;
x ^= yesnum; y ^= yesnum;
if(op == 1)
{
int ori = mp[a[x]],pr = 0,sf = 0;
s[ori].erase(x);
set <int> :: iterator it = s[ori].lower_bound(x);
if(it != s[ori].begin())
{
it--;
pr = *it;
it++;
}
if(it != s[ori].end()) sf = *it;
if(sf) t.modify_pre(1,n,sf,pr,1);
s[ori].erase(x);
a[x] = y;
if(mp.find(a[x]) == mp.end()) mp[a[x]] = ++cnt;
ori = mp[a[x]]; pr = 0; sf = 0;
s[ori].insert(x);
it = s[ori].find(x);
if(it != s[ori].begin())
{
it--;
pr = *it;
it++;
}
it++;
if(it != s[ori].end()) sf = *it;
t.modify_pre(1,n,x,pr,1);
if(sf) t.modify_pre(1,n,sf,x,1);
t.modify_del(1,n,x,a[x] - a[x + 1],1);
if(x > 1) t.modify_del(1,n,x - 1,a[x - 1] - a[x],1);
t.modify_num(1,n,x,a[x],1);
}
else
{
cin>>k;
k ^= yesnum;
pair <int,int> num = t.query_num(1,n,x,y,1);
if(k == 0)
{
if(num.first == num.second) puts("Yes"),++yesnum;
else puts("No");
continue;
}
if(x == y) {puts("Yes"),++yesnum; continue;}
if(num.first - num.second == 1ll * (y - x) * k && abs(t.query_del(1,n,x,y - 1,1)) == k && t.query_pre(1,n,x,y,1) < x) puts("Yes"),++yesnum;
else puts("No");
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话