傻b错误调一天系列

原题:

大意:给你一个数列a,字词两种操作:

1.把c[l]改成r

2.询问在区间[l,r]中,有多少个极大子区间满足子区间里的数全部一样,且在[x,y]范围内

(对于满足条件的区间A,若不存在满足条件的区间B使得A包含于B,则称A为极大子区间)

序列问题,要求复杂度O(nlogn),联想cdq分治

值域可以容斥拆成[1,l-1]和[1,r]两个询问,即把询问转化为区间中数小于等于x的数有多少个

可以把初始数列看成0,然后用修改操作代替初始数列

那么现在就存在偏序:若修改A的时间小于询问B,且A的值小于B的值,则A可以给B提供贡献

对于计算贡献,我们建一个线段树,字词单点修改,并查询有多少个不同的非0极大子区间,这个比较好写

初始按时间排序,然后按值域分治

然后这题就做完了马

反例:

6 3
1 1 4 5 1 4
2 1 6 2 5
1 6 1
2 1 6 2 5

上面的做法会输出3 3,正确答案却是3 2

考试的时候我写这个做法然后深度自闭

出错的原因是因为我们按值域分治,那么当第6个数(被视为操作1 6 4)和第三个操作(2 1 6 2 5)分到一个分治区间时,因为操作2(1 6 1)被分到左边的分治区间了,所以不会把代表第6个数的操作覆盖掉,这时第6个数就给第3个操作产生了贡献(尽管第三个操作进行时它已经被覆盖掉了)

更换提供贡献的顺序是不行的,这是个死循环,不管是用前序、中序或后序cdq分治都无法解决,根本原因是操作2(1 6 1)实际上给操作3(2 1 6 2 5)一个负贡献(它把一个本来合法的区间变得不合法),却因为值域没有达到操作3的范围([2,5])而被忽略了

这个负贡献在分治过程中无法统计(至少我没找到方法)

正确做法是

只考虑一个区间中的左端点那个数,新建一个数组b,对于每个b[i],若a[i]==a[i-1]则b[i]为0否则为a[i]

问题就转化为求区间[l+1,r]中有多少个数,最后单独特判a[l]是否在区间[x,y]内

这个就是经典cdq分治问题,由于数的值域为[1,n],所以用权值线段树(树状数组)可以方便地统计贡献

这种做法和上一种的根本区别在于一个修改操作是覆盖,而另一个是增添和删除,在分治中第二种统计贡献比第一种简单直接很多

然后我就迎来了这题第二次自闭,在晚上10:30写出正确代码后找bug到11:30,直至次日下午5:00才发现问题

只因为一句话的位置:

这是对操作1的处理,注释代码为原位置

如果把d[i]赋值写在后边,就会导致当r==c[l]时,d[i]={0,0,0,0,0,0,0},而我在判断是否应该输出的时候是靠d[i].mk是否为1来判断的

这就导致当r==c[l]发生时,会有修改操作被当成查询操作多输出一个数,自然会WA

这个bug我花了这么长时间没找出来,一个很重要的原因时总在原地打转,算法基本框架检查过很多遍没有问题了,就应该去思考一些细节,尤其是看起来很奇怪很特殊的部分

我倒是看了细节,但是偏偏没有注意到这么奇怪而特殊的一个特判

这个故事也告诉我们有时候睡一觉休息一下bug就自己出来了,不能盲目死磕

代码:

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int rd(){int z=,mk=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')mk=-; ch=getchar();}
while(ch>=''&&ch<=''){z=(z<<)+(z<<)+ch-''; ch=getchar();}
return z*mk;
}
struct nds{int mk,x,y,z,id,ans;}a[]; int atp=;
int n,m;
int b[],c[];
nds q[];
int v[];
int ans[];
nds d[];
inline int lbt(int x){ return x&-x;}
void mdf(int x,int y){ for(;x<=n;x+=lbt(x)) v[x]+=y;}
int qry(int x){ int bwl=; for(;x;x-=lbt(x)) bwl+=v[x]; return bwl;}
void cdq(int x,int y,int l,int r){
if(x>=y) return ;
if(l>r) return ;
if(l==r){
for(int i=x;i<=y;++i){
if(!a[i].mk) mdf(a[i].y,a[i].z);
else a[i].ans+=qry(a[i].z)-qry(a[i].y-);
}
for(int i=x;i<=y;++i)if(!a[i].mk) mdf(a[i].y,-a[i].z);
return ;
}
int md=(l+r)>>;
int cnt1=;
for(int i=x;i<=y;++i){
if(a[i].x<=md) ++cnt1;
if(!a[i].mk && a[i].x<=md) mdf(a[i].y,a[i].z);
if(a[i].mk && a[i].x>md) a[i].ans+=qry(a[i].z)-qry(a[i].y-);
}
for(int i=x;i<=y;++i)if(!a[i].mk && a[i].x<=md)
mdf(a[i].y,-a[i].z);
int hd1=x,hd2=x+cnt1;
for(int i=x;i<=y;++i){
if(a[i].x<=md) q[hd1++]=a[i];
else q[hd2++]=a[i];
}
for(int i=x;i<=y;++i) a[i]=q[i];
cdq(x,hd1-,l,md),cdq(hd1,y,md+,r);
}
void prvs(){
atp=;
for(int i=;i<=m;++i) ans[i]=;
}
int main(){
//freopen("ddd.in","r",stdin);
cin>>n>>m;
prvs();
for(int i=;i<=n;++i) c[i]=rd();
c[]=,c[n+]=;
for(int i=;i<=n;++i){
if(c[i]!=c[i-]) a[++atp]=(nds){,i,c[i],,-,};
b[i]=c[i];
}
int mk,l,r,ql,qr;
for(int i=;i<=m;++i){
mk=rd();
if(mk==){
l=rd(),r=rd();
d[i]=(nds){mk,l,r,,,i};
if(r==c[l]) continue;
if(c[l]!=c[l-]) a[++atp]=(nds){,l,c[l],-,i,};
if(r!=c[l-]) a[++atp]=(nds){,l,r,,i,};
if(l<n){
if(r==c[l+]) a[++atp]=(nds){,l+,c[l+],-,i,};
if(c[l]==c[l+]) a[++atp]=(nds){,l+,c[l+],,i,};
}
c[l]=r;
//d[i]=(nds){mk,l,r,0,0,i}; Attention!!!
}
else{
l=rd(),r=rd(),ql=rd(),qr=rd();
a[++atp]=(nds){,r,ql,qr,i,};
a[++atp]=(nds){-,l,ql,qr,i,};
d[i]=(nds){mk,l,r,ql,qr,i};
}
}
cdq(,atp,,n);
for(int i=;i<=atp;++i)if(a[i].mk) ans[a[i].id]+=a[i].mk*a[i].ans;
for(int i=;i<=m;++i){
if(d[i].mk==) b[d[i].x]=d[i].y;
else printf("%d\n",ans[i]+(b[d[i].x]>=d[i].z && b[d[i].x]<=d[i].id));
}
return ;
}

【icpc2019网络赛南昌站】Yukino With Subinterval的更多相关文章

  1. ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval

    ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval 题目大意:给一个长度为n,值域为[1, n]的序列{a},要求支持m次操作: 单点修改 1 pos val 询 ...

  2. 2019南昌网络赛  I. Yukino With Subinterval 树状数组套线段树

    I. Yukino With Subinterval 题目链接: Problem Descripe Yukino has an array \(a_1, a_2 \cdots a_n\). As a ...

  3. 2018ICPC网络赛(焦作站)E题题解

    一.题目链接 二.题意 给定一棵树,有四种操作: $1\ u\ v\ x$:把节点$u$到$v$路径上的所有点的权值乘以$x$: $2\ u\ v\ x$:把节点$u$到$v$路径上的所有点的权值加上 ...

  4. 2018ICPC网络赛(焦作站)K题题解

    一.题目链接 https://nanti.jisuanke.com/t/31720 二.题意 给$N$种船只,第$i$种船的载重量是$V_i$,数量是$2^{C_i}-1$.接下来有$Q$次询问,每次 ...

  5. 2018ICPC网络赛(徐州站)A题题解

    一.题目链接 https://nanti.jisuanke.com/t/31453 二.题意 给定$N$个位置,$2^k$种颜色,让你去涂色,条件是相邻的两种颜色类型异或值的二进制表示不全为$1$(以 ...

  6. 2019南昌网络赛I:Yukino With Subinterval(CDQ) (树状数组套主席树)

    题意:询问区间有多少个连续的段,而且这段的颜色在[L,R]才算贡献,每段贡献是1. 有单点修改和区间查询. 思路:46min交了第一发树套树,T了. 稍加优化多交几次就过了. 不难想到,除了L这个点, ...

  7. 2019 ICPC 南昌网络赛I:Yukino With Subinterval(CDQ分治)

    Yukino With Subinterval Yukino has an array a_1, a_2 \cdots a_na1,a2⋯*a**n*. As a tsundere girl, Yuk ...

  8. 南昌邀请赛网络赛 D.Match Stick Game(dp)

    南昌邀请赛网络赛 D.Match Stick Game 题目传送门 题目就会给你一个长度为n的字符串,其中\(1<n<100\).这个字符串是一个表达式,只有加减运算符,然后输入的每一个字 ...

  9. dp--2019南昌网络赛B-Match Stick Game

    dp--2019南昌网络赛B-Match Stick Game Xiao Ming recently indulges in match stick game and he thinks he is ...

随机推荐

  1. 第12课.经典问题解析(const;指针和引用)

    问题1:const什么时候为只读变量?什么时候是常量? const常量的判别准则: a.只有用字面量初始化的const常量才会进入符号表(直接初始化过的const为常量) b.被使用其他变量初始化的c ...

  2. 2019-07-30 C#基础知识学习

    继承和多态 接口与抽象类的区别:1.在接口中仅能定义成员,但是不能有具体的实现:抽象类除了抽象成员以外,其他成员有具体的实现.2.在接口中不能声明字段,并且不能声明任何私有成员,成员不能包含任何修饰符 ...

  3. PAT A1005 Spell It Right (20)

    书中AC代码 #include <cstdio> #include <cstring> #include <iostream> char num[10][10] = ...

  4. dos2unix、diff命令

    一.dos2unix:将DOS格式文件转化成UNIX格式文件 语法: dos2unix [选项] [文件...] [-n INFILE输出文件...]           unix2dos [选项] ...

  5. IIS和apache并存windows服务器

    方法三: 将apache设为使用80端口,IIS使用其它端口,比如81,然后将apache作为IIS的代理.速度有影响.在httpd.conf里面,取消下面四行的注释:LoadModule proxy ...

  6. 怎样理解NodeList的动态集合与静态集合

    NodeList 有两种, 一种是动态集合, 一种是静态集合, 所谓动态集合, 主要是 Node.prototype.childNodes; 返回的子节点集合对文档的节点增删改会即时改变; 而静态集合 ...

  7. asp.net 4.Redirect重定向和文件图片上传

    1.Response.Redirect 如图所示: 1.用户点击修改按钮, 浏览器向服务器发送一个POST请求 http://localhost:6543/UpdateUser.ashx 2.服务器的 ...

  8. X-Router软路由设置

    一 内网:     ip   192.168.0.1      掩码  255.255.255.0      网关   (空)     DNS   202.96.128.68(佛山的)手动写入 二 外 ...

  9. 经典算法,yuv与rgb互转,查表法,让你的软件飞起来

    代码的运算速度取决于以下几个方面 1. 算法本身的复杂度,比如MPEG比JPEG复杂,JPEG比BMP图片的编码复杂. 2. CPU自身的速度和设计架构 3. CPU的总线带宽 4. 您自己代码的写法 ...

  10. Const指针 、 指向const的指针 、引用、指针

    1. const指针和 指向const的指针 指向const的指针: 不允许通过指针来改变其指向的const值 const double *cptr *cptr = 42;  // error! 指针 ...