*X. P7708「Wdsr-2.7」八云蓝自动机 Ⅰ

摘自 分治与根号数据结构学习笔记 第三部分 莫队 例题 X.。

一道莫队好题。私以为本题最有价值的地方在于对单点修改的转化以及对交换两个数的处理:需要维护原来每个位置现在的位置,以及现在每个位置原来的位置。

注意到这个单点修改并不方便实现(如果是单点加就好做了),我们可以使用一个小技巧将其转化为交换两个数,即新建一个 \(a_c=k\),并将其看做 \(a_x\) 与 \(a_c\) 交换。这一步非常巧妙,因为它消灭了单点修改这一麻烦的操作。

对于多次询问一段区间的操作结果,我们通常需要使用莫队实现,因此考虑区间在伸缩时需要维护什么东西。为了支持在操作序列最前面加入交换两个数的操作,我们不难想到维护:

  • 序列 \(a\) 在操作后变成了什么样。

  • \(pos_i\) 表示现位置 \(i\) 是原来的哪个位置。

  • \(rev_i\) 表示原位置 \(i\) 现在在哪。

  • \(add_i\) 表示原位置 \(i\) 上的数被查询了多少次。

  • 当右端点右移 \(r-1\to r\) 时:

    • 若第 \(r\) 个操作是交换 \(x,y\),则交换 \(a_x,a_y\),\(pos_x,pos_y\),\(rev_{pos_x},rev_{pos_y}\)。
    • 若第 \(r\) 个操作是查询 \(x\),则令 \(ans\gets ans+a_x\),\(add_{pos_x}\gets add_{pos_x}+1\)。
  • 当左端点左移 \(l+1\to l\) 时:

    • 若第 \(l\) 个操作是交换 \(x,y\),注意我们相当于交换 “原位置” 的两个数,因此对答案有影响。令 \(del=a_{rev_y}-a_{rev_x}\),答案需加上 \(del\times (add_x-add_y)\),即计算原来的 \(a_x,a_y\) 即现在的 \(a_{rev_x},a_{rev_y}\) 在交换后的贡献变化量。此外,交换 \(a_{rev_x},a_{rev_y}\) \(add_x,add_y\),\(rev_x,rev_y\) 以及 \(pos_{rev_x},pos_{rev_y}\)。
    • 若第 \(l\) 个操作是查询 \(x\),则令 \(ans\gets ans+a_{rev_x}\),\(add_x\gets add_x+1\),意义显然。

右端点左移和左端点右移的情况分别与上述两种情况相似,不再赘述。时间复杂度 \(\mathcal{O}(n\sqrt n)\)。

const int N=4e5+5;
const int B=666;
uint n,m,q,cnt,a[N],id[N],op[N],x[N],y[N];
struct query{
int l,r,blk,id;
bool operator < (const query &v) const {
return blk!=v.blk?blk<v.blk:blk&1?r>v.r:r<v.r;
}
}c[N]; uint ans,res[N],pos[N],rev[N],add[N];
int main(){
cin>>n>>m,cnt=n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=m;i++){
cin>>op[i]>>x[i]; if(op[i]!=3)cin>>y[i];
if(op[i]==1)a[++cnt]=y[i],op[i]=2,y[i]=cnt;
}
for(int i=1;i<=cnt;i++)pos[i]=rev[i]=i;
cin>>q;
for(int i=1,l,r;i<=q;i++)cin>>l>>r,c[i]={l,r,l/B,i};
sort(c+1,c+q+1);
for(int i=1,l=1,r=0;i<=q;i++){
while(r<c[i].r){
r++;
if(op[r]==2){
swap(pos[x[r]],pos[y[r]]),swap(a[x[r]],a[y[r]]);
swap(rev[pos[x[r]]],rev[pos[y[r]]]);
}
else ans+=a[x[r]],add[pos[x[r]]]++;
}
while(l>c[i].l){
l--;
if(op[l]==2){
uint del=a[rev[y[l]]]-a[rev[x[l]]];
swap(rev[x[l]],rev[y[l]]),ans+=(add[x[l]]-add[y[l]])*del;
swap(a[rev[x[l]]],a[rev[y[l]]]);
swap(pos[rev[x[l]]],pos[rev[y[l]]]),swap(add[x[l]],add[y[l]]);
}
else ans+=a[rev[x[l]]],add[x[l]]++;
}
while(r>c[i].r){
if(op[r]==2){
swap(pos[x[r]],pos[y[r]]),swap(a[x[r]],a[y[r]]);
swap(rev[pos[x[r]]],rev[pos[y[r]]]);
}
else ans-=a[x[r]],add[pos[x[r]]]--;
r--;
}
while(l<c[i].l){
if(op[l]==2){
uint del=a[rev[y[l]]]-a[rev[x[l]]];
swap(rev[x[l]],rev[y[l]]),ans+=(add[x[l]]-add[y[l]])*del;
swap(a[rev[x[l]]],a[rev[y[l]]]);
swap(pos[rev[x[l]]],pos[rev[y[l]]]),swap(add[x[l]],add[y[l]]);
}
else ans-=a[rev[x[l]]],add[x[l]]--;
l++;
}
res[c[i].id]=ans;
}
for(int i=1;i<=q;i++)cout<<res[i]<<"\n";
return 0;
}

最新文章

  1. SAP CRM 性能小技巧
  2. .Net 初步学习笔记之一——.Net 平台与.Net FrameWork框架的关系
  3. Flask + WSGI + Nginx 云部署
  4. DP URAL 1244 Gentlemen
  5. CodeForces 549G Happy Line
  6. LA 3971 (二分) Assemble
  7. centos6.5安装tomcat8.0.15
  8. Android Activity和intent
  9. TStack,TQueue,TObjectList,TObjectStack等等
  10. Python跨目录调用模块
  11. MySQL 忘记root密码解决方法,基于Ubuntu 14.10
  12. ajax与后台交互案例
  13. javascript prop和attr的区别
  14. python使用PDB进行调试
  15. 让Mysql支持Emoji表情,解决[Err] 1366 - Incorrect string value: &#39;\xF0\xA3\x84\x83&#39;
  16. GMA Round 1 大吉大利,晚上吃鸡
  17. 【netcore基础】ubuntu 16.04 搭建.net core 2.1 linux 运行环境 nginx反向代理 supervisor配置自启动
  18. js 比大小
  19. 接入层高性能缓存技术nginx+redis利器OpenResty
  20. python windows环境下文档备份

热门文章

  1. kafka错误之 Topic xxx not present in metadata after 60000 ms
  2. Java基础之原生JDBC操作数据库
  3. Noip模拟52 2021.9.13
  4. 高并发场景下JVM调优实践之路
  5. objcopy使用
  6. JAVA笔记6__抽象类/接口/多态/instanceof关键字、父类设计法则
  7. uni-app使用wx-canvas实现微信小程序上显示地图map和坐标geo
  8. ssl 原理和建立连接过程
  9. leetcode 剪绳子系列
  10. ITextRenderers html生成pdf 分页+横向