序言

此日志分为四部分。

00:00是开始打代码的时间。

最开始打完代码(没有debug)大约用了两小时。

part1-20210323

02:30

生成新节点时,没有给随机权值。

02:41

upd中,sum更新时没有先清空,没有加上右儿子的sum。

02:46

操作12没问题

操作3会RE+WA

5 100000
0 0 0 1 1
3 1 5

change1中第7行,merge中顺序反了。

change1中第11行,分裂出的子树错误(\(z\rightarrow y\))。

03:01

split1中if(k>l[i])应为if(k>=l[i])

分裂左/右子树反了。

03:07

assign中,\(l\not=1\&\&r=n\)中\(lv[y]=x\)的case中,没有拓展同色区间。root=merge(x,node(l,n,v));改为root=merge(x,node(ll[y],n,v));

1和l看错了root=merge(root,node(1,rr[y],v));应为root=merge(root,node(l,rr[y],v));

x和1搞错了if(lv[y]!=x)应为if(lv[y]!=v)

03:10~11:40

睡觉

11:57

change1中,修改y树的根时work(y,1,flag==1?1:-1);应为work(y,0,flag?1:-1);

12:02

dfs中始终只会spread rootspread(root);改为spread(x);

12:33

spread中只要有一种标记没有打,则就不会下传标记if(!lazy[x][0]||!lazy[x][1]) return;应为if(!lazy[x][0]&&!lazy[x][1]) return;

过样例,WA+MLE+RE

12:45

hack:

5 10000
1 0 0 0 0
4 1 5

树的结构错误的变成了

1 1 1
3 5 0

操作4错误

12:55

打模拟赛

14:22

上面的错误是debug错了,输出树的结构没有spread。

15:32

忘记强制在线了,WA-ALL(说明只差一点点了!)

15:32

写了对拍(无加密)

10 100
1 1 0 1 0 0 0 1 0 0
3 3 6
5 1 4
5 4 7
7 7 8
5 5 6
3 10 10
4 6 9
3 8 9
3 5 10
7 2 9
5 6 9
6 3 10
4 1 1
1 7 7
4 4 8
2 4 7
5 5 9
1 9 9
7 1 4
5 3 4
2 2 8
2 9 10
7 8 10
2 2 7
7 3 9

我输出

1
2
2
3
7

std

1
5
4
3
7

为什么修改无效?

16:30

午餐

17:20

午休

18:12

下午好

下午没有做什么,所以暂停了计时。

18:56

晚上好。加油吧,\(Vanilla\_chan\)!

19:25

重写了upd,assign函数

/**************************************************************
* Problem: 5066
* Author: Vanilla_chan
* Date: 20210323
* E-Mail: Vanilla_chan@outlook.com
**************************************************************/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<limits.h>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#ifdef TH
#define debug printf("Now is %d\n",__LINE__);
#else
#define debug
#endif
#ifdef ONLINE_JUDGE
char buf[1<<23],* p1=buf,* p2=buf,obuf[1<<23],* O=obuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
using namespace std; namespace oi
{
inline bool isdigit(const char& ch)
{
return ch<='9'&&ch>='0';
}
inline bool isalnum(const char& ch)
{
return (ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch>='0'&&ch<='9');
}
struct istream
{
char ch;
bool fu;
template<class T>inline istream& operator>>(T& d)
{
fu=d=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') fu=1,ch=getchar();
d=ch-'0';ch=getchar();
while(isdigit(ch))
d=(d<<3)+(d<<1)+(ch^'0'),ch=getchar();
if(fu) d=-d;
return *this;
}
inline istream& operator>>(string& str)
{
str.clear();
for(;!isdigit(ch);ch=getchar());
while(isalnum(ch))
str+=ch,ch=getchar();
return *this;
}
}cin;
inline int read()
{
int x=0,fu=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') fu=-1,ch=getchar();
x=ch-'0';ch=getchar();
while(isdigit(ch)) { x=x*10+ch-'0';ch=getchar(); }
return x*fu;
}
int G[55];
template<class T>inline void write(T x)
{
int g=0;
if(x<0) x=-x,putchar('-');
do { G[++g]=x%10;x/=10; } while(x);
for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n');
}
};
using namespace oi; #define N 6000010 int n,m;
int a[N];
int root;
int key[N];
int l[N],r[N];//平衡树上一个点所代表的一段区间[l,r]
int ll[N],rr[N];//平衡树上一个点的子树代表的一段区间[ll,rr]
bool val[N];//当前点代表区间的值0/1
int ls[N],rs[N];//左右儿子
int cnt[N][2];//以当前点为根的子树内的0/1段数量
int mn[N][2];//以当前点为根的子树内,最短的0/1段的长度
int sum[N];//当前点的子树和
bool lv[N],rv[N];//当前点的子树的边界位置的值
int lazy[N][2];
int tot;
void upd(int x)
{
if(ls[x]) ll[x]=ll[ls[x]];
else ll[x]=l[x];
if(rs[x]) rr[x]=rr[rs[x]];
else rr[x]=r[x];
cnt[x][val[x]]=1;
cnt[x][!val[x]]=0;
mn[x][val[x]]=r-l+1;
mn[x][!val[x]]=n+1;
if(val[x]) sum[x]=r[x]-l[x]+1;
else sum[x]=0;
if(ls[x]) lv[x]=lv[ls[x]];
else lv[x]=val[x];
if(rs[x]) rv[x]=rv[rs[x]];
else rv[x]=val[x];
if(ls[x])
{
cnt[x][0]+=cnt[ls[x]][0];
cnt[x][1]+=cnt[ls[x]][1];
mn[x][0]=min(mn[x][0],mn[ls[x]][0]);
mn[x][1]=min(mn[x][1],mn[ls[x]][1]);
sum[x]+=sum[ls[x]];
}
if(rs[x])
{
cnt[x][0]+=cnt[rs[x]][0];
cnt[x][1]+=cnt[rs[x]][1];
mn[x][0]=min(mn[x][0],mn[rs[x]][0]);
mn[x][1]=min(mn[x][1],mn[rs[x]][1]);
sum[x]+=sum[rs[x]];
}
}
int node(int L,int R,bool vv)
{
tot++;
l[tot]=L;
r[tot]=R;
val[tot]=vv;
key[tot]=rand();
ls[tot]=rs[tot]=0;
lazy[tot][0]=lazy[tot][1]=0;
upd(tot);
return tot;
}
void work(int x,bool flag,int k)
{
//if(!x||!k) return;
lazy[x][flag]+=k;
if(flag)
{
if(val[x]) r[x]+=k;
else l[x]+=k;
}
else
{
if(val[x]) l[x]-=k;
else r[x]-=k;
}
mn[x][0]-=k;
mn[x][1]+=k;
sum[x]+=k*cnt[x][1];
}
void spread(int x)
{
//if(!lazy[x][0]&&!lazy[x][1]) return;
if(ls[x]) work(ls[x],0,lazy[x][0]),work(ls[x],1,lazy[x][1]);
if(rs[x]) work(rs[x],0,lazy[x][0]),work(rs[x],1,lazy[x][1]);
lazy[x][0]=lazy[x][1]=0;
}
int merge(int x,int y)
{
if(!x) return y;
if(!y) return x;
if(key[x]>key[y])
{
spread(x);
rs[x]=merge(rs[x],y);
upd(x);
return x;
}
else
{
spread(y);
ls[y]=merge(x,ls[y]);
upd(y);
return y;
}
}
void split1(int i,int k,int& x,int& y)
{
if(!i)
{
x=y=0;
return;
}
spread(i);
if(k>=l[i])
{
split1(rs[i],k,rs[i],y);
x=i;
}
else
{
split1(ls[i],k,x,ls[i]);
y=i;
}
upd(i);
}
void split2(int i,int k,int& x,int& y)
{
if(!i)
{
x=y=0;
return;
}
spread(i);
if(k<=r[i])
{
split2(ls[i],k,x,ls[i]);
y=i;
}
else
{
split2(rs[i],k,rs[i],y);
x=i;
}
upd(i);
}
int ask(int l,int r)
{
int x,y,z;
split2(root,l,x,y);//可以切多但是不能切少
split1(y,r,y,z);//所以这里切最左侧时,应是小于当前块的右边界
int ans=sum[y];//这样即使有可能让l在最左边的一块内部,但是下面会将多余的减去。反之同理
if(lv[y]) ans-=l-ll[y];
if(rv[y]) ans-=rr[y]-r;
root=merge(x,merge(y,z));
return ans;
}
void assign(int l,int r,bool v)
{
int x,y,z;
if(l==1)
{
if(r==n)
{
root=node(l,r,v);
return;
}
else
{
split1(root,r+1,x,y);
//if(rv[x]!=v) root=merge(merge(node(1,r,v),node(r+1,rr[x],!v)),y);
//else root=merge(node(1,rr[x],v),y);
if(rv[x]!=v)
{
root=node(1,r,v);
root=merge(root,node(r+1,rr[x],!v));
}
else
{
root=node(1,rr[x],v);
}
root=merge(root,y);
}
}
else
{
if(r==n)
{
split2(root,l-1,x,y);
//if(lv[y]!=v) root=merge(x,merge(node(ll[y],l-1,!v),node(l,n,v)));
//else root=merge(x,node(ll[y],n,v));
root=x;
if(lv[y]!=v)
{
root=merge(root,node(ll[y],l-1,!v));
root=merge(root,node(l,n,v));
}
else
{
root=merge(root,node(ll[y],n,v));
}
}
else
{
split2(root,l-1,x,y);
split1(y,r+1,y,z);
root=x;
/*
if(lv[y]!=v)
{
root=merge(root,node(ll[y],l-1,!v));
if(rv[y]!=v)
{
root=merge(root,node(l,r,v));
root=merge(root,node(r+1,rr[y],!v));
}
else
{
root=merge(root,node(l,rr[y],v));
}
}
else
{
if(rv[y]!=v)
{
root=merge(root,node(ll[y],r,v));
root=merge(root,node(r+1,rr[y],!v));
}
else
{
root=merge(root,node(ll[y],rr[y],v));
}
}
root=merge(root,z);
*/
if(lv[y]!=v)
{
root=merge(root,node(ll[y],l-1,!v));
if(rv[y]!=v)
{
root=merge(root,node(l,r,v));
root=merge(root,node(r+1,rr[y],!v));
}
else
{
root=merge(root,node(l,rr[y],v));
}
}
else
{
if(rv[y]!=v)
{
root=merge(root,node(ll[y],r,v));
root=merge(root,node(r+1,rr[y],!v));
}
else
{
root=merge(root,node(ll[y],rr[y],v));
}
root=merge(root,z);
} }
}
}
void change1(int l,int r,bool flag)//向左传递flag
{
int x,y,z,t;
split1(root,l-1,x,y);
split1(y,r,y,z);
if(y&&lv[y])
{
split2(x,ll[y]-1,x,t);
y=merge(t,y);
}
if(y&&!rv[y])
{
split2(y,rr[x],y,t);
z=merge(t,z);
}
if(y)
{
work(y,0,flag?1:-1);
}
root=merge(x,merge(y,z));//FHQ-Treap常规操作
}
void change2(int l,int r,bool flag)
{
int x,y,z,t;
split2(root,r+1,y,z);
split2(y,l,x,y);
if(y&&rv[y])
{
split1(z,rr[y]+1,t,z);
y=merge(y,t);
}
if(y&&!lv[y])
{
split1(y,ll[y],t,y);
x=merge(x,t);
}
if(y)
{
work(y,1,flag?1:-1);
}
root=merge(x,merge(y,z));
}
int dfs(int x)
{
//debug cout<<"x="<<x<<endl;
spread(x);
if(l[x]==r[x]+1) return l[x];
else if(ls[x]&&(!mn[ls[x]][0]||!mn[ls[x]][1]))
{
return dfs(ls[x]);
}
else return dfs(rs[x]);
}
void del()
{
int t=dfs(root);
int x,y,z;
split2(root,t-1,x,y);
split1(y,t,y,z);
root=merge(x,merge(node(ll[y],rr[y],r[y]+1==l[y]?!val[y]:val[y]),z));
}
void init()
{
int res=1;
for(int i=2;i<=n;i++)
{
if(a[i]!=a[i-1])
{
root=merge(root,node(res,i-1,a[res]));
res=i;
}
}
root=merge(root,node(res,n,a[res]));
}
void out(int x)
{
spread(x);
if(ls[x]) out(ls[x]);
cout<<"id="<<x<<" "<<l[x]<<" "<<r[x]<<" "<<val[x]<<endl;
if(rs[x]) out(rs[x]);
}
int op,x,y;
int lastans; int main()
{
freopen("5066.in","r",stdin);
//freopen(".out","w",stdout);
oi::cin>>n>>m;
srand(20050228);
for(int i=1;i<=n;i++) oi::cin>>a[i];
init();
while(m--)
{
op=read();
x=read();
y=read();
//x^=lastans;
//y^=lastans;
if(op==1)
{
assign(x,y,0);
}
else if(op==2)
{
assign(x,y,1);
}
else if(op==3)
{
change1(x+1,y,1);
}
else if(op==4)
{
change2(x,y-1,1);
}
else if(op==5)
{
change2(x,y-1,0);
}
else if(op==6)
{
change1(x+1,y,0);
}
else
{
write(lastans=ask(x,y));
}
//out(root);
while(!mn[root][0]||!mn[root][1]) del();
debug
out(root);
}
return 0;
}

显然这份代码不能过。能过就折寿了。

part2-20210327~20210328

在家与学校之间的地铁上debug。

upd函数中,r[x]-l[x]+1写成r-l+1

重构代码,用指针全部重写。

\(0pts\).

part3-20210329

整个下午都在调指针。

过了自己的样例……还是\(0pts\).

又造出了一组hack数据!

debug……80pts

数组开小了,\(3\times 10^6\)。

还是80pts……

卡常,卡常,跑完操,没吃晚饭。

找lxl小姐姐请求放大时限(然后把最后一组数据调成了8s)还是过不去。

果然,越可爱就会越毒瘤吗……

part4-20210330

进入了漫长的卡常期……

delete废弃的指针(反正不会MLE)

把所有的==!=都改成了^

while(!root->mn[0]||!root->mn[1]) update();改写到3|4|5|6内部去,减少四个if

将随机数改写成了s*=13并\(\text{unsigned int}\)自然溢出。

spread等函数全部inline,并判断有lazy时再进入函数操作(if放到函数外面减少调用次数)。

将快读变为传址。

删除无关头文件。

split1/2中的k既不会修改也不会冲突,就去掉这个参数改为全局变量吧。

可以过\(\#27\)了!

将随机数改写成s=(s<<1)+s.等价于s*=3

ans变为全局变量,同时就可以不用lastans了。

对于update中的\(x\)同理。

我傻了,随机数怎么可以写成s*=3?那样对于一段内的key不久全是单调的了嘛!

换成s*=19260817

可以过\(\#31\)了!\(90pts\)

ask,assign,change1.change2函数中的*x,*y,*z,*t设置成全局的。

将有\(bool\)变量参数的函数全部分程两个,比如\(change1\)写成\(change10\)和\(change11\),\(change2\)写成\(change20\)和\(change21\),\(assign\)写成\(assign0\)和\(assign1\),\(work\)写成\(work0\)和\(work1\)。

关于随机数,试了s=s*3^3在\(\text{unsigned short int}\)下虽然跑的很满很快,但是实际效果不如s*=19260817在\(\text{unsigned int}\)。于是我就换成了s*=1000000009在\(\text{long long}\)下的自然溢出。

考虑到读取\(3\times 10^6\)个\(\text{bool}\)变量用读取\(\text{int}\)的快读还是可圈可点的。所以写了readbool

inline void readbool(bool &xx)
{
ch=getchar();
while(!isdigit(ch)) ch=getchar();
xx=ch-'0';
}

\(\textbf{2021-03-31 08:00:25 thus,AC.}\)


第129发过了。

洛谷 P5066 [Ynoi2014] 人人本着正义之名debug-log的更多相关文章

  1. 洛谷 P4062 - [Code+#1]Yazid 的新生舞会 的线性做法

    洛谷题面传送门 一个线性做法. \(n\log n\) 解法可以戳这里查看 首先回顾一下 \(n\log n\) 解法的过程:我们对于每一个数 \(x\),考察其出现位置,设为 \(t_1,t_2,t ...

  2. C++ 洛谷 2014 选课 from_树形DP

    洛谷 2014 选课 没学树形DP的,看一下. 首先要学会多叉树转二叉树. 树有很多种,二叉树是一种人人喜欢的数据结构,简单而且规则.但一般来说,树形动规的题目很少出现二叉树,因此将多叉树转成二叉树就 ...

  3. 「树形DP」洛谷P2607 [ZJOI2008]骑士

    P2607 [ZJOI2008]骑士 题面: 题目描述 Z 国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬. 最近发生了一件可怕的事情,邪恶的 ...

  4. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

  5. 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.

    没有上司的舞会  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...

  6. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...

  7. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

  8. 洛谷P1710 地铁涨价

    P1710 地铁涨价 51通过 339提交 题目提供者洛谷OnlineJudge 标签O2优化云端评测2 难度提高+/省选- 提交  讨论  题解 最新讨论 求教:为什么只有40分 数组大小一定要开够 ...

  9. 洛谷P1371 NOI元丹

    P1371 NOI元丹 71通过 394提交 题目提供者洛谷OnlineJudge 标签云端评测 难度普及/提高- 提交  讨论  题解 最新讨论 我觉得不需要讨论O long long 不够 没有取 ...

  10. 洛谷P1538迎春舞会之数字舞蹈

    题目背景 HNSDFZ的同学们为了庆祝春节,准备排练一场舞会. 题目描述 在越来越讲究合作的时代,人们注意的更多的不是个人物的舞姿,而是集体的排列. 为了配合每年的倒计时,同学们决定排出——“数字舞蹈 ...

随机推荐

  1. IOS 内付 asp.net mvc 服务器端验证

    上代码: public class AppStorePayApp { public int VerifyReceipt(string receipt, out string product_id, o ...

  2. 自己修改的一款Typora学术主题Academic-zh-vq

    这款typora主题是在Academic-Zh主题的基础上修改而来的. 主题衍生路径: 官方Academic主题-->zh-academic主题-->Academic-Zh主题--> ...

  3. Netty基础—1.网络编程基础一

    大纲 1.什么是OSI开放系统互连 2.OSI七层模型各层的作用 3.TCP/IP协议的简介 4.TCP和UDP的简介 5.TCP连接的三次握手 6.TCP连接的四次挥手 7.TCP/IP中的数据包 ...

  4. LaTeX使用记录

    安装与使用 曾在Windows10下装过MikTeX,并配合vscode插件LaTeX Workshop使用过一段时间:这次转到wsl2中,并使用texlive,所以插件的配置json需要小修改 参考 ...

  5. LayerSkip: 使用自推测解码加速大模型推理

    自推测解码是一种新颖的文本生成方法,它结合了推测解码 (Speculative Decoding) 的优势和大语言模型 (LLM) 的提前退出 (Early Exit) 机制.该方法出自论文 Laye ...

  6. Qt QCheckBox设置复选框的大小

    文章目录 Qt设计QCheckBox样式表 QCheckBox的各部分代表的样式表 Qt QCheckBox设置复选框的大小 Qt设计QCheckBox样式表 QCheckBox的各部分代表的样式表 ...

  7. Ubuntu如何下载nvidia驱动和Cuda Toolkit

    Ubuntu如何下载nvidia驱动和Cuda Toolkit 前言 ‍ 手快不小心把 nvidia​ 的某个东西删除了,现在不得不全部卸载后再重新安装了. 我再也不敢在不确认内容的情况下,确认删除了 ...

  8. Golang 入门 : Go语言介绍

    简介 Go 语言又称 Golang,由 Google 公司于 2009 年发布,近几年伴随着云计算.微服务.分布式的发展而迅速崛起,跻身主流编程语言之列,和 Java 类似,它是一门静态的.强类型的. ...

  9. 项目实战 TS

    项目实战 TS 通用技巧 新手先 any 再填坑,老手先定义数据结构写逻辑 遇到新场景,没把握快速,先用 any 再填坑,填坑的过程也是 TS 技能满满提升的过程. TS 发现潜在问题 1)复杂逻辑, ...

  10. [每日算法 - 华为机试] LeetCode1160. 拼写单词

    题目入口 力扣https://leetcode.cn/problems/find-words-that-can-be-formed-by-characters/ 题目概述 给你一份『词汇表』(字符串数 ...