题解 链表 (chain)
首先考虑没有修改怎么做。
两种做法。
想到询问的形式为保留 的连通块个数,那么先将全部数字按照权值排序,然后从后往前做一遍并查集,并同时统计连通块的数量,在询问时只需二分找到第一个 的位置,将这个位置的答案输出即可。注意考虑答案为 的情况。
但是显然,上面的做法是很难拓展为有修改的情况的,所以这是就要提到另一种做法。
考虑对于一个 ,哪些情况下会产生新的连通块,显然当 且 时,在 和 之间会断开,产生新的连通块。如果考虑对于一个答案,有多少种这样的情况,由于 会变,所以我们不得不在 遍历一遍,总时间复杂度是 。
考虑对于一种情况,会对多少种答案产生贡献,显然,若 ,那么,当 ,该种情况都会对所有 产生 的贡献。询问时将对应的 输出即可。这是一个区间加,单点查的操作,前缀和+差分即可。
如果加上修改操作,那么对于一个位置上的 ,将其换成 ,只需将之前的贡献消除,将新的贡献加上即可。区间修单点查,容易想到树状数组。
点击查看代码
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef unsigned long long ULL; LL read() { LL sum=0,flag=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') flag=-1; c=getchar();} while(c>='0'&&c<='9') {sum=sum*10+c-'0'; c=getchar();} return sum*flag; } const int N=5e5+10,M=5e5; int n,m; int tr[N]; int a[N]; int lowbit(int x) { return x&(-x); } void change(int nd,int x) { for(int i=nd;i<=M;i+=lowbit(i)) tr[i]+=x; } int query(int nd) { int sum=0; for(int i=nd;i>=1;i-=lowbit(i)) sum+=tr[i]; return sum; } void add(int l,int r,int x) { change(l,x); change(r+1,-x); } int main() { n=read(); m=read(); for(int i=1;i<=n;i++) { a[i]=read(); if(a[i-1]<a[i]) add(a[i-1]+1,a[i],1); } int lst=0; while(m--) { string opt; int x,y; cin>>opt; if(opt=="Q") { x=read(); x^=lst; lst=query(x); cout<<lst<<'\n'; } else { x=read(); y=read(); x^=lst; y^=lst; if(a[x-1]<a[x]) add(a[x-1]+1,a[x],-1); if(a[x]<a[x+1]) add(a[x]+1,a[x+1],-1); a[x]=y; if(a[x-1]<a[x]) add(a[x-1]+1,a[x],1); if(a[x]<a[x+1]) add(a[x]+1,a[x+1],1); } } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效