HDU - 6087 Rikka with Sequence (可持久化treap+倍增+重构)
感谢Dream_Lolita的题解,经过无数次失败的尝试之后终于AC了...
线段树是维护区间信息的强大工具,但它的形态是固定的,只支持修改和删除操作,不支持插入、反转、复制、分裂合并等操作,而treap支持。这道题有个区间复制的操作,因此只能用treap来代替了。
注意几个坑点:
1.对于操作2,当k<r-l+1时,不是将[l-k,r-k]中的元素直接替换到[l,r]上,而是将[l-k,l-1]中的元素复制多次再替换到[l,r]上,因此需要对[l-k,l-1]区间反复自我merge直至长度大于等于r-l+1,类似倍增的方式。
2.如果对每个结点设置一个静态的随机因子,那么对区间进行复制时,会产生大量重复的随机因子,严重影响树的平衡性。因此可以去掉随机因子,在对结点u,v进行merge的时候动态取一个随机数rnd,检查rnd%(siz[u]+siz[v])与siz[u]的关系来决定以哪种方式进行合并。考虑到评测OS是Windows,rand函数的上限只有2^15-1,因此可以采用rand()<<15|rand()的方法将两个rand函数拼凑起来,这样上限就扩大到2^30-1了。
3.操作3中的merge可以不用可持久化,但操作2中的merge必须可持久化,否则会出现莫名其妙的错误(这里查错查了很久,我暂时也说不清为什么)
4.本题对内存的限制非常严格,因此需要定期检查结点数量,如果快要超过内存上限了,就要对整个序列进行暴力重构。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=28e5+,inf=0x3f3f3f3f;
int ch[N][],val[N],siz[N],tot,n,m,rt,A,q[],nq;
ll sum[N];
#define l(u) ch[u][0]
#define r(u) ch[u][1]
int rnd() {return rand()<<|rand();}
int newnode(int x) {int u=++tot; val[u]=sum[u]=x,siz[u]=,l(u)=r(u)=; return u;}
int cpy(int u) {int w=++tot; val[w]=val[u],sum[w]=sum[u],siz[w]=siz[u],l(w)=l(u),r(w)=r(u); return w;}
void pu(int u) {siz[u]=siz[l(u)]+siz[r(u)]+,sum[u]=sum[l(u)]+sum[r(u)]+val[u];}
void sp(int w,int k,int& u,int& v) {
if(!w) {u=v=; return;}
if(k>=siz[l(w)]+)u=cpy(w),sp(r(w),k-(siz[l(w)]+),r(u),v),pu(u);
else v=cpy(w),sp(l(w),k,u,l(v)),pu(v);
}
void mg(int& w,int u,int v,int f=) {
if(!u||!v) {w=u|v; return;}
if(rnd()%(siz[u]+siz[v])<siz[u])w=(f?cpy(u):u),mg(r(w),r(u),v,f);
else w=(f?cpy(v):v),mg(l(w),u,l(v),f);
pu(w);
}
void upd(int& u,int l,int r,int k) {
int L,M,R,M2;
sp(u,l-,L,R),sp(L,l-k-,L,M);
while(siz[M]<r-l+)mg(M,M,M,);
sp(M,r-l+,M,M2),sp(u,r,L,R),sp(L,l-,L,M2);
mg(L,L,M,),mg(u,L,R,);
}
void upd2(int& u,int v,int l,int r) {
int L,M,R,M2;
sp(v,r,L,R),sp(L,l-,L,M);
sp(u,r,L,R),sp(L,l-,L,M2);
mg(L,L,M),mg(u,L,R);
}
ll qry(int& u,int l,int r) {
int L,M,R;
sp(u,r,L,R),sp(L,l-,L,M);
ll ret=sum[M];
mg(L,L,M),mg(u,L,R);
return ret;
}
void dfs(int u) {if(!u)return; dfs(l(u)),q[nq++]=val[u],dfs(r(u));}
void build(int& u,int l=,int r=n-) {
if(l>r) {u=; return;}
int mid=(l+r)>>;
u=newnode(q[mid]);
build(l(u),l,mid-),build(r(u),mid+,r),pu(u);
}
void rebuild() {tot=siz[A],nq=,dfs(rt),build(rt);}
int main() {
srand(time());
scanf("%d%d",&n,&m);
for(int i=; i<n; ++i)scanf("%d",&q[i]);
build(A),rt=A;
while(m--) {
int f,l,r,k;
scanf("%d%d%d",&f,&l,&r),l,r;
if(f==)scanf("%d",&k);
if(f==)printf("%lld\n",qry(rt,l,r));
else if(f==)upd(rt,l,r,k);
else if(f==)upd2(rt,A,l,r);
if(tot>)rebuild();
}
return ;
}
HDU - 6087 Rikka with Sequence (可持久化treap+倍增+重构)的更多相关文章
- 判断相同区间(lazy) 多校8 HDU 5828 Rikka with Sequence
// 判断相同区间(lazy) 多校8 HDU 5828 Rikka with Sequence // 题意:三种操作,1增加值,2开根,3求和 // 思路:这题与HDU 4027 和HDU 5634 ...
- HDU 5828 Rikka with Sequence (线段树)
Rikka with Sequence 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5828 Description As we know, Rik ...
- hdu 5828 Rikka with Sequence 线段树
Rikka with Sequence 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5828 Description As we know, Rik ...
- hdu 5204 Rikka with sequence 智商不够系列
Rikka with sequence Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.p ...
- HDU 5828 Rikka with Sequence(线段树 开根号)
Rikka with Sequence Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Othe ...
- HDU 5828 Rikka with Sequence (线段树+剪枝优化)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5828 给你n个数,三种操作.操作1是将l到r之间的数都加上x:操作2是将l到r之间的数都开方:操作3是 ...
- HDU 5828 Rikka with Sequence(线段树)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5828 [题目大意] 给出一个数列,要求支持区间加法,区间开方和区间和查询操作. [题解] 考虑开方 ...
- HDU 5828 Rikka with Sequence(线段树区间加开根求和)
Problem DescriptionAs we know, Rikka is poor at math. Yuta is worrying about this situation, so he g ...
- HDU 5828 Rikka with Sequence
好久没写线段树了,这题作为一个回味.. 第一种操作的话,就是一个延迟标记. 第二种操作可以暴力更新下去,但是有一个优化,如果某区间内所有值都是一样的,或者最大值和最小值相差1,那么到此结束,不要继续往 ...
随机推荐
- cisco 访问控制列表
LAB-A:Lab-A(config)#host Lab-A Lab-A(config)#interface Ethernet0/0 LAB-A(config-if)#ip address 172. ...
- PHP7 开启Zend Opcache
PHP7 开启Zend Opcache 作为PHP这10年来最大的版本与性能升级,PHP7在多次的测试中都表现出很夸张的性能提升,然而,为了让它能发挥出最大的性能,需要手动开启PHP自带的opcach ...
- linux 使用tmux
一. 什么是tmux 1.1. tmux 是两个单词的缩写,即“Terminal MultipleXer”,意思是“终端复用器“ 1.2. tmux 结构 1.2.1. tmux主要由三层: < ...
- Git_基础命令
gitinit//初始化一个Git仓库" role="presentation">gitinit//初始化一个Git仓库gitinit//初始化一个Git仓库 gi ...
- Nginx启动错误 Failed to read PID from file /run/nginx.pid 的处理方法
问题产生原因 因为 nginx 启动需要一点点时间,而 systemd 在 nginx 完成启动前就去读取 pid file 造成读取 pid 失败 解决方法 让 systemd 在执行 ExecSt ...
- js 控制加载|移除 script 与 link 文件
js 加载 script 文件 /** * 加载 script 文件 * @param src */ function loadScript(src) { var addSign = true; va ...
- kinit: Bad encryption type while getting initial credentials
描述:RHEL 6.x主机执行kinit -kt命令报如下错误 [heboan@localhost~]$ kinit -kt heboan.keytab heboan kinit: Bad encry ...
- Linux经典操作
1.Linux批量终止在运行中包含某个字符串的所有进程. ps -ef|grep celery | grep -v grep|cut -c 9-15|xargs kill -9
- 正则替换replace中$1的用法
一.repalce定义 用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串. 1 2 3 4 5 stringObject.replace(regexp/substr,repla ...
- 本地存储cookie,localStorage,sessionStorage
常见的前端存储有老朋友 cookie,短暂的 sessionStorage,和简单强大的localStorage 他们之间的区别有以下几点 1.. cookie在浏览器和服务器间来回传递.而sessi ...