平衡树并不是之前没写过,觉得有必要把平衡树变成考场上能敲的东西,也就是说,考一道诸如“维修数列”这样的送分题,要能拿满分。

维修数列。给定一个数列支持以下操作:

输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。

以上都是复制的。

这一次呢肯定比上一次敲的快了那么一点,但没有达到要求,总时间大概3h,还需很大的提升。

调试时间。。inf

主要的调试时间在边界的处理上。

1、某个子树大小。本来子树大小如果不影响答案计算的话是可以直接把边界加进来的,但是这里有求和和区间赋值,因此有必要知道区间除了边界外的真实大小。

这一次的处理方式是:假设边界点是不存在的,即size=0.这样引发的一系列调整如下:

首先,up时size的更新要注意不要加上边界点:

a[x].size=a[p].size+a[q].size+(x!=lbod && x!=rbod);

其次,find时对边界点单独处理下:

        if (K>a[root].size) ans=rbod;
else if (K==) ans=lbod;

在find时,找第K个数,如果往右走要这么写:

K-=a[x].size-a[a[x].son[]].size,x=a[x].son[];

而不要写K-=a[a[x].son[0]].size+1,这样相当于默认x的size是1,而x有可能是边界点。

2、连边必up,访子必down。up和down在一些细节会忘了打。最典型的是splay:splay(x,top)表示把x旋到top下,如果top不为0的话应up(top);再如find以及其他类似操作时心存侥幸以为不用down,但实际上这题有区间翻转操作,左右儿子会变,因此必须down。

3、读入。注意'-'号。

4、答案。注意边界点既要做到能传递区间答案,本身又不能对答案产生影响。这里解决的方法是在up的时候进行如下判断:

        if (x!=lbod && x!=rbod) a[x].Maxsum=max(a[p].Maxsum,max(a[q].Maxsum,a[p].rsum+a[x].v+a[q].lsum));
else if (x==lbod) a[x].Maxsum=q?a[q].Maxsum:-0x3f3f3f3f;
else a[x].Maxsum=p?a[p].Maxsum:-0x3f3f3f3f;

以及在区间赋值时进行如下操作:

        if (x==lbod || x==rbod) a[x].v=;
if (a[x].size==) a[x].lsum=a[x].rsum=a[x].Maxsum=-0x3f3f3f3f;

调试时果断选择区间输出。但静态查错还是不能少。

总的来说,有待提高。

 #include<string.h>
#include<stdlib.h>
#include<stdio.h>
//#include<assert.h>
#include<algorithm>
//#include<iostream>
using namespace std; int n,m;
#define maxn 500011
int num[maxn]; struct Splay
{
struct Node
{
int son[],fa;
bool rev,hbe; int be;
int v,size,sum,Maxsum,lsum,rsum;
}a[maxn];
int root,sta[maxn],top,lbod,rbod;
Splay()
{
top=;
for (int i=;i<=top;i++) sta[i]=i;
root=lbod=; rbod=;
a[].Maxsum=-0x3f3f3f3f;
a[lbod].Maxsum=a[rbod].Maxsum=a[lbod].lsum=a[lbod].rsum=a[rbod].lsum=a[rbod].rsum=-0x3f3f3f3f;
a[lbod].v=a[lbod].size=a[lbod].sum=a[lbod].rev=a[lbod].hbe=;
a[rbod].v=a[rbod].size=a[rbod].sum=a[rbod].rev=a[rbod].hbe=;
a[lbod].son[]=rbod; a[rbod].fa=lbod;
}
void up(int x)
{
if (!x) return;
int &p=a[x].son[],&q=a[x].son[];
a[x].sum=a[p].sum+a[q].sum+a[x].v;
a[x].size=a[p].size+a[q].size+(x!=lbod && x!=rbod);
if (x!=lbod && x!=rbod) a[x].Maxsum=max(a[p].Maxsum,max(a[q].Maxsum,a[p].rsum+a[x].v+a[q].lsum));
else if (x==lbod) a[x].Maxsum=q?a[q].Maxsum:-0x3f3f3f3f;
else a[x].Maxsum=p?a[p].Maxsum:-0x3f3f3f3f;
a[x].lsum=max(a[p].lsum,a[p].sum+a[x].v+a[q].lsum);
a[x].rsum=max(a[q].rsum,a[q].sum+a[x].v+a[p].rsum);
}
void besingle(int x,int v)
{
if (!x) return;
a[x].v=a[x].be=v; a[x].hbe=;
if (x==lbod || x==rbod) a[x].v=;
a[x].sum=a[x].size*v;
if (v>=) a[x].lsum=a[x].rsum=a[x].Maxsum=a[x].sum;
else a[x].lsum=a[x].rsum=,a[x].Maxsum=v;
if (a[x].size==) a[x].lsum=a[x].rsum=a[x].Maxsum=-0x3f3f3f3f;
}
void revsingle(int x)
{
if (!x) return;
a[x].rev^=; int t=a[x].son[]; a[x].son[]=a[x].son[]; a[x].son[]=t;
t=a[x].lsum; a[x].lsum=a[x].rsum; a[x].rsum=t;
}
void down(int x)
{
int &p=a[x].son[],&q=a[x].son[];
if (a[x].hbe) {besingle(p,a[x].be); besingle(q,a[x].be); a[x].hbe=;}
if (a[x].rev) {revsingle(p); revsingle(q); a[x].rev=;}
}
int dsta[maxn],dtop;
void download(int x)
{
dtop=;
for (int i=x;i;i=a[i].fa) dsta[++dtop]=i;
while (dtop) down(dsta[dtop--]);
}
void rotate(int x)
{
const int y=a[x].fa,z=a[y].fa;
bool w=(x==a[y].son[]);
a[x].fa=z;
if (z) a[z].son[y==a[z].son[]]=x;
a[y].son[w^]=a[x].son[w];
if (a[x].son[w]) a[a[x].son[w]].fa=y;
a[x].son[w]=y;
a[y].fa=x;
up(y); up(z);
}
void splay(int x,int top)
{
if (!x) return;
download(x);
while (a[x].fa!=top)
{
const int y=a[x].fa,z=a[y].fa;
if (z!=top)
{
if ((x==a[y].son[])^(y==a[z].son[])) rotate(x);
else rotate(y);
}
rotate(x);
}
up(x);
if (!top) root=x; else up(top);
}
int find(int K)
{
// cout<<K<<endl;
int x=root,ans=;
if (K>a[root].size) ans=rbod;
else if (K==) ans=lbod;
else while (x)
{
// cout<<x<<' '<<K<<endl;
down(x);
if (x==lbod) x=a[x].son[];
else if (x==rbod) x=a[x].son[];
else if (a[a[x].son[]].size<K-) K-=a[x].size-a[a[x].son[]].size,x=a[x].son[];
else ans=x,x=a[x].son[];
}
if (ans) splay(ans,);
return ans;
}
void New(int &x) {x=sta[top--];}
void build(int &x,int L,int R)
{
if (L>R) {x=; return;}
New(x);
// cout<<x<<' '<<L<<' '<<R<<endl;
const int mid=(L+R)>>;
a[x].v=a[x].sum=a[x].Maxsum=num[mid]; a[x].size=; a[x].hbe=a[x].rev=;
if (num[mid]>=) a[x].lsum=a[x].rsum=num[mid];
else a[x].lsum=a[x].rsum=;
build(a[x].son[],L,mid-);
if (a[x].son[]) a[a[x].son[]].fa=x;
build(a[x].son[],mid+,R);
if (a[x].son[]) a[a[x].son[]].fa=x;
up(x);
}
void build(int &x,int n) {build(x,,n);}
void insert(int pos,int tot)
{
int x=find(pos),y=a[x].son[];
// cout<<x<<' '<<y<<endl;
while (a[y].son[]) down(y),y=a[y].son[];
splay(y,x);
build(a[y].son[],tot);
a[a[y].son[]].fa=y;
up(y); up(x);
}
void recycle(int x)
{
sta[++top]=x;
if (a[x].son[]) recycle(a[x].son[]);
if (a[x].son[]) recycle(a[x].son[]);
}
void Delete(int pos,int tot)
{
int y=find(pos+tot);
// test();
int x=find(pos-);
// test();
splay(y,x);
if (a[y].son[]) recycle(a[y].son[]);
a[y].son[]=; up(y); up(x);
}
void Be(int pos,int tot,int v)
{
int y=find(pos+tot),x=find(pos-);
splay(y,x);
besingle(a[y].son[],v);
up(y); up(x);
}
void Rev(int pos,int tot)
{
int y=find(pos+tot),x=find(pos-);
splay(y,x);
revsingle(a[y].son[]);
up(y); up(x);
}
int Sum(int pos,int tot)
{
// cout<<pos<<' '<<tot<<endl;
int y=find(pos+tot);
// test();
int x=find(pos-);
// test();
splay(y,x);
return a[a[y].son[]].sum;
}
int Maxsum() {return a[root].Maxsum;}
// void test(int x)
// {
// if (!x) return;
//// down(x);
// test(a[x].son[0]);
// cout<<x<<' '<<a[x].v<<" size"<<a[x].size<<" sum"<<a[x].sum<<" Maxsum"<<a[x].Maxsum
// <<" lsum"<<a[x].lsum<<" rsum"<<a[x].rsum<<" son0 "<<a[x].son[0]<<" son1 "<<a[x].son[1]
// <<" be"<<a[x].be<<" rev"<<a[x].rev<<endl;
// test(a[x].son[1]);
// }
// void test() {test(root);cout<<endl;}
}t; int qread()
{
char c;int s=,t=; while ((c=getchar())<'' || c>'') (c=='-' && (t=-));
do s=s*+c-''; while ((c=getchar())>='' && c<=''); return s*t;
}
int main()
{
n=qread(); m=qread();
for (int i=;i<=n;i++) num[i]=qread();
t.insert(,n);
// t.test();
char c;
for (int i=,x,y,z;i<=m;i++)
{
// cout<<i<<"!!!"<<t.a[t.root].size<<' '<<t.a[0].size<<endl;
while ((c=getchar())<'A' || c>'Z');
if (c=='I')
{
while (((c=getchar())>='A' && c<='Z') || c=='-');
x=qread(); y=qread();
for (int j=;j<=y;j++) num[j]=qread();
t.insert(x,y);
}
else if (c=='D')
{
while (((c=getchar())>='A' && c<='Z') || c=='-');
x=qread(); y=qread();
t.Delete(x,y);
}
else if (c=='R')
{
while (((c=getchar())>='A' && c<='Z') || c=='-');
x=qread(); y=qread();
t.Rev(x,y);
}
else if (c=='G')
{
while (((c=getchar())>='A' && c<='Z') || c=='-');
x=qread(); y=qread();
printf("%d\n",t.Sum(x,y));
}
else
{
c=getchar(); c=getchar();
if (c=='K')
{
while (((c=getchar())>='A' && c<='Z') || c=='-');
x=qread(); y=qread(); z=qread();
t.Be(x,y,z);
}
else
{
while (((c=getchar())>='A' && c<='Z') || c=='-');
printf("%d\n",t.Maxsum());
}
}
// t.up(t.lbod);
// t.test();
}
return ;
}

一练Splay之维修数列第一次的更多相关文章

  1. 【BZOJ-1500】维修数列 Splay

    1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 11047  Solved: 3460[Submit][Statu ...

  2. bzoj 1500: [NOI2005]维修数列 splay

    1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 6556  Solved: 1963[Submit][Status ...

  3. [BZOJ 1500]维修数列 [Splay Tree从进阶到住院]

    历尽艰辛终于A掉了这题QwQ 贴COGS评论区几句话=.= 策爷:"splay/块状链表的自虐题.".深刻理解到如果没有M倾向就不要去写这题了.. -Chenyao2333 记得b ...

  4. 【BZOJ1500】【NOI2005】维修数列(Splay)

    [BZOJ1500][NOI2005]维修数列(Splay) 题面 不想再看见这种毒瘤题,自己去BZOJ看 题解 Splay良心模板题 真的很简单 我一言不发 #include<iostream ...

  5. [BZOJ1500][NOI2005]维修数列 解题报告 Splay

    Portal Gun:[BZOJ1500][NOI2005]维修数列 有一段时间没写博客了,最近在刚数据结构......各种板子背得简直要起飞,题目也是一大堆做不完,这里就挑一道平衡树的题来写写好了 ...

  6. BZOJ 1500: [NOI2005]维修数列 (splay tree)

    1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 4229  Solved: 1283[Submit][Status ...

  7. 【BZOJ1500】[NOI2005]维修数列 Splay

    [BZOJ1500][NOI2005]维修数列 Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行 ...

  8. splay模板三合一 luogu2042 [NOI2005]维护数列/bzoj1500 [NOI2005]维修数列 | poj3580 SuperMemo | luogu3391 【模板】文艺平衡树(Splay)

    先是维修数列 题解看这里,但是我写的跑得很慢 #include <iostream> #include <cstdio> using namespace std; int n, ...

  9. [NOI2005] 维修数列

    1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 8397  Solved: 2530 Description In ...

随机推荐

  1. 转 Docker和hadoop

    2017-06-21 朱洁 Docker很热,怎么形容?感觉开源除了spark技术,就是docker了,甚至把Go语言也带火了,把Go在TIOBE的排名从百名外带入主流语言的行列. Docker快成救 ...

  2. 转】Nodejs对MongoDB模糊查询

    原博文出自于: http://blog.fens.me/category/%E6%95%B0%E6%8D%AE%E5%BA%93/page/4/ 感谢! Posted: Jul 1, 2013 Tag ...

  3. .NET框架概述

    .NET战略目标: 任何时候(when),任何地方(where),使用任何工具(what)都能通过.NET的服务获得网络上的任何信息. .NET优势: 1.提供了一个面向对象的编程环境,完全支持面向对 ...

  4. 写给W小姐的一封信

    生活 琐碎 Hallo,Preaty.对于跟人说话,我很不擅长如何开头.我不知道什么样的开头是符合我在别人心目中我应有的形象.我不知道什么样的开头符合别人预想中与我相匹配的内容.或者说什么的开头才是一 ...

  5. R in action 读书笔记(1)--第五章:高级数据管理

    5.2.1数学函数 函数 描述 abs(x) 绝对值 sqrt(x) 平方根 ceiling(x) 不小于x的最小整数 floor(x) 不大于x的最大整数 trunc(x) 向0的方向截取的X中的整 ...

  6. 重构28-Rename boolean method(重命名布尔方法)

    你也可以说这并不是一个真正的重构,因为方法实际上改变了,但这是一个灰色地带,可以开放讨论.一个拥有大量布尔类型参数的方法将很快变得无法控制,产生难以预期的行为.参数的数量将决定分解的方法的数量.来看看 ...

  7. [转] 随机数是骗人的,.Net、Java、C为我作证

    (转自:随机数是骗人的,.Net.Java.C为我作证 - 杨中科   原文日期:2014.05.12) 几乎所有编程语言中都提供了"生成一个随机数"的方法,也就是调用这个方法会生 ...

  8. SourceTree 常用操作

    1.Sourcetree 每次拉取提交都需要输入密码(是有多个项目,他们的账户不一样) 输入以下命令: git config --global credential.helper osxkeychai ...

  9. JavaSE-23 注解

    学习要点 注解的概念 注解分类 读取注解信息 注解概述 1  元数据 定义 描述数据的数据. 用处 文档编制.编译器检查.代码分析等 2  Java注解 Annotation in JDK5.0——将 ...

  10. JavaSE-14 异常处理

    学习要点 使用try-catch-finally处理异常 使用throw.throws抛出异常 异常及其分类 log4j记录日志 异常 1  异常的定义 异常是指在程序的运行过程中所发生的不正常的事件 ...