正题

题目链接:https://www.luogu.com.cn/problem/P5113


题目大意

一个长度为 n n n的序列 a a a, m m m次要求支持以下操作

  1. 将区间 [ l , r ] [l,r] [l,r]都变为 x x x。
  2. 询问区间 [ l , r ] [l,r] [l,r]的和。
  3. 将第 x x x次操作 1 1 1撤销。

强制在线

1 ≤ n , m ≤ 1 0 5 , 1 ≤ a i , x ≤ 1 0 9 1\leq n,m\leq 10^5,1\leq a_i,x\leq 10^{9} 1≤n,m≤105,1≤ai​,x≤109

操作 1 1 1的个数不超过 65000 65000 65000


解题思路

考虑分块,那么我们需要解决散块和整块的问题。

考虑使用领接表(单向链表)来维护每个数字和块的历史状态,那么对于散块来说我们直接添加新节点连接,然后撤回时给对应操作打上标记,再在邻接表上一直跳到没有打标记的节点即可。
在散块的个体处理完后我们需要重构维护整块信息。

现在主要是整块如何处理的问题,一般的我们会有一个 a n s i ans_i ansi​表示第 i i i块的和,和同上面个体一样的,每个块都有一个领接表来表明它的历史状态。

对于一个块来说,不是整块修改产生贡献的部分个体的修改时间比整块的修改时间要晚,而且撤回操作只会让整个块的修改时间变早,而修改操作一定会让整个块的修改时间变成最晚的。

结合上面的性质,我们大概能得到一个做法。对于每个块,我们维护一个每个数散块的修改时间升序排序的序列,这样越在前面的数越容易被整块的修改影响。也就是必定是影响一个前缀,假设这个前缀的位置为 x x x,那么撤回操作只会让 x x x向前移动,而整块修改只会让 x x x直接跳到 R R R,这两种情况分开维护的话就会发现对于每次重构后的块, x x x最多移动 n \sqrt n n ​次,也就是这个移动的复杂度均摊进了重构中。

而这个升序序列只需要在散块修改的时候才需要重构,需要使用到基数排序。

需要注意的细节是开始所有数都没有被修改但是有值,所以块内的初值很重要。

时间复杂度: O ( n n ) O(n\sqrt n) O(nn ​)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const ll N=1e5+10,Q=320,P=256;
ll n,m,tot,cnt,qnt,a[N],ls[N];
ll b[Q],rk[N],rks[N],res[N],xs[N];
ll w[N],ql[N],qr[N],val[N*Q],nxt[N*Q];
ll L[Q],R[Q],lst[Q],ans[Q],lp[Q],pos[N];
bool flag[N];
void Addl(ll &x,ll w)
{val[++tot]=w;nxt[tot]=x;x=tot;return;}
void PushUp(ll &x)
{while(flag[val[x]])x=nxt[x];return;}
void Rebuild(ll x){for(ll i=0;i<P;i++)b[i]=0;for(ll i=L[x];i<=R[x];i++)b[val[ls[i]]%P]++;for(ll i=1;i<P;i++)b[i]+=b[i-1];for(ll i=L[x];i<=R[x];i++)b[val[ls[i]]%P]--,rk[L[x]+b[val[ls[i]]%P]]=i;for(ll i=0;i<P;i++)b[i]=0;for(ll i=L[x];i<=R[x];i++)b[val[ls[i]]/P]++;for(ll i=1;i<P;i++)b[i]+=b[i-1];for(ll i=R[x];i>=L[x];i--)b[val[ls[rk[i]]]/P]--,rks[L[x]+b[val[ls[rk[i]]]/P]]=rk[i];for(ll i=L[x];i<=R[x];i++)xs[i]=val[ls[rks[i]]];res[R[x]]=xs[R[x]]?w[xs[R[x]]]:a[rks[R[x]]];for(ll i=R[x]-1;i>=L[x];i--)res[i]=res[i+1]+(xs[i]?w[xs[i]]:a[rks[i]]);lp[x]=L[x];while(lp[x]<=R[x]&&xs[lp[x]]<val[lst[x]])lp[x]++;ans[x]=(lp[x]<=R[x])?res[lp[x]]:0;ans[x]+=(lp[x]-L[x])*w[val[lst[x]]];return;
}
void Change(ll l,ll r,ll val){ll x=pos[l],y=pos[r];++qnt;w[qnt]=val;ql[qnt]=l;qr[qnt]=r;if(x==y){for(ll i=l;i<=r;i++)Addl(ls[i],qnt);Rebuild(x);return;}for(ll i=x+1;i<y;i++)Addl(lst[i],qnt),ans[i]=val*(R[i]-L[i]+1);for(ll i=l;i<=R[x];i++)Addl(ls[i],qnt);for(ll i=L[y];i<=r;i++)Addl(ls[i],qnt);Rebuild(x);Rebuild(y);return;
}
ll GetI(ll p){if(!ls[p]&&!lst[pos[p]])return a[p];return w[max(val[lst[pos[p]]],val[ls[p]])];
}
ll Ask(ll l,ll r){ll x=pos[l],y=pos[r],sum=0;if(x==y){for(ll i=l;i<=r;i++)sum+=GetI(i);return sum;}for(ll i=x+1;i<y;i++)sum+=ans[i];for(ll i=l;i<=R[x];i++)sum+=GetI(i);for(ll i=L[y];i<=r;i++)sum+=GetI(i);return sum;
}
void Remake(ll x){if(!flag[val[lst[x]]])return;PushUp(lst[x]);if(xs[R[x]]<val[lst[x]]){ans[x]=(R[x]-L[x]+1)*w[val[lst[x]]];return;}lp[x]--;while(lp[x]>=L[x]&&xs[lp[x]]>=val[lst[x]])lp[x]--;lp[x]++;ans[x]=(lp[x]<=R[x])?res[lp[x]]:0;ans[x]+=(lp[x]-L[x])*w[val[lst[x]]];return;
}
void Withdraw(ll p){ll l=ql[p],r=qr[p];flag[p]=1;ll x=pos[l],y=pos[r];if(x==y){for(ll i=l;i<=r;i++)PushUp(ls[i]);Rebuild(x);return;}for(ll i=x+1;i<y;i++)Remake(i);for(ll i=l;i<=R[x];i++)PushUp(ls[i]);for(ll i=L[y];i<=r;i++)PushUp(ls[i]);Rebuild(x);Rebuild(y);return;
}
signed main()
{//  freopen("data.in","r",stdin);
//  freopen("data.out","w",stdout);scanf("%lld%lld",&n,&m);ll T=sqrt(n);for(ll i=1;i<=n/T;i++)L[i]=R[i-1]+1,R[i]=i*T;cnt=n/T;if(R[cnt]!=n)++cnt,L[cnt]=R[cnt-1]+1,R[cnt]=n;for(ll i=1;i<=cnt;i++)for(ll j=L[i];j<=R[i];j++)pos[j]=i;for(ll i=1;i<=n;i++)scanf("%lld",&a[i]),ans[pos[i]]+=a[i];for(ll i=1;i<=cnt;i++)Rebuild(i);ll las=0;while(m--){ll op;scanf("%lld",&op);if(op==1){ll l,r,w;scanf("%lld%lld%lld",&l,&r,&w);l^=las;r^=las;Change(l,r,w);}else if(op==2){ll l,r;scanf("%lld%lld",&l,&r);l^=las;r^=las;printf("%lld\n",las=Ask(l,r));}else{ll x;scanf("%lld",&x);x^=las;Withdraw(x);}}return 0;
}

P5113-Sabbat of the witch【分块,基数排序】相关推荐

  1. 【洛谷P5113】—魔女的夜宴Sabbat of the witch(分块+基数排序)

    传送门 绫地宁宁天下第一! 考虑对于每一个块,用一个 s e t set set来维护每次整块的覆盖 对于每个点再维护一个 s e t set set表示对散块的覆盖 将块内每个点按照最后一次覆盖的时 ...

  2. 2018十二月刷题列表

    Preface \(2018\)年的尾巴,不禁感慨自己这一年的蜕变只能用蜕变来形容了. 而且老叶说我们今年没的参加清北冬令营可以参加CCF在广州二中举办的冬令营,只要联赛\(390+\)就应该可以报. ...

  3. 数据结构源码笔记(C语言):英文单词按字典序排序的基数排序

    //实现英文单词按字典序排序的基数排序算法#include<stdio.h> #include<malloc.h> #include<string.h>#defin ...

  4. 数据结构源码笔记(C语言):基数排序

    //实现基数排序算法#include<stdio.h> #include<malloc.h> #include<string.h>#define MAXE 20 / ...

  5. 数据结构源码笔记(C语言):分块法查找

    //实现分块法查找的算法#include<stdio.h> #include<malloc.h> #include<malloc.h>#define MAXL 10 ...

  6. CF966E-May Holidays【虚树,分块】

    正题 题目链接:https://codeforces.ml/contest/966/problem/E 题目大意 nnn个点的一棵树,每个点有一个tit_iti​,每次修改一个点是否为关键点,每次修改 ...

  7. 基数排序简介及其并行化

    基数排序是线性时间排序算法中性能最好的排序算法.本文将简要概括其算法思想.串行实现及其并行化. 1.简介 1.1算法思想 基数排序属于"分配式排序"(distribution so ...

  8. java 二分搜索获得大于目标数的第一位_程序员常用查找算法(顺序、二分、插值、分块、斐波那契)...

    顺序查找 基本思想 属于线性查找和无序查找,从一端开始顺序扫描,直到找到与目标值value相等的元素. 这是最基本的查找方法,也是时间复杂度最高的查找算法. 在数据过多时,这种方法并不适用. 代码实现 ...

  9. 数据库 大数据访问及分区分块优化方案

    本文导读:当系统要满足每秒数万次的读写请求的需求时,我们可以用分布式计算.编写优良的程序代码.对海量数据进行分区操作.建立广泛的索引.建立缓存机制.加大虚拟内存.分批处理.使用数据仓库和多维数据库存储 ...

最新文章

  1. 6月书讯 | 如果有一本书伴随你十年编程,那一定是它
  2. 如何使用OSI模型排除故障
  3. R语言中的esttab命令_R语言︱基本函数、统计量、常用操作函数
  4. Python字典排序sorted无效,用匿名函数lambda解决
  5. 刀片服务器和机架服务器性能,刀片服务器与机架服务器的区别是什么 刀片服务器与机架服务器的区别介绍...
  6. 通过七牛云建立私有图床
  7. ruby 新建对象_Ruby中的面向对象编程
  8. 相机标定(4) 矫正畸变 undistort()和initUndistortRectifyMap()
  9. 拓端tecdat|R语言贝叶斯非参数模型:密度估计、非参数化随机效应meta分析心肌梗死数据
  10. 【计算机网络】Web服务器的配置
  11. 不拽术语,如何通俗地讲解机器学习?
  12. 预约洗车/美容/维修/家政/保养/上门洗车预约小程序源码及管理系统
  13. mysql 提取字符串首字母_SQL获取字段字符串中文首字母
  14. 你的深度思考能力,是如何一步步被毁掉的?
  15. C++ 设置桌面壁纸
  16. Java+webdriver的自动化测试框架搭建
  17. wireshark常见协议包分析1
  18. 解决android studio编译的速度慢,安装apk过慢的问题
  19. mac与windows下各自的md5、sha1、sha256命令行校验工具
  20. 高中计算机高效课堂和有效教学模式论文,高效课堂教学模式

热门文章

  1. Facebook:情侣杀手?
  2. 基于redis的分布式redissson
  3. 瑞典公司推出可防止新冠病毒和其他细菌传播的新型薄膜
  4. Xen Server虚拟机数据丢失的恢复过程
  5. 因为相信所以看见,既然看见注定坚信《14》
  6. 密码学中一些加减乘除法优化
  7. 利用C语言打印表白动态爱心
  8. HTML+JS猜数字游戏
  9. 关于重装完系统以后引导出错导致电脑无法开机的问题(File:\EFI\Microsoft\Boot\BCD,Error code:0xc000000f)
  10. Maxdos 9.3不能引导系统进入Maxdos