【icpc2019网络赛南昌站】Yukino With Subinterval
傻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的更多相关文章
- ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval
ACM-ICPC 2019南昌网络赛I题 Yukino With Subinterval 题目大意:给一个长度为n,值域为[1, n]的序列{a},要求支持m次操作: 单点修改 1 pos val 询 ...
- 2019南昌网络赛 I. Yukino With Subinterval 树状数组套线段树
I. Yukino With Subinterval 题目链接: Problem Descripe Yukino has an array \(a_1, a_2 \cdots a_n\). As a ...
- 2018ICPC网络赛(焦作站)E题题解
一.题目链接 二.题意 给定一棵树,有四种操作: $1\ u\ v\ x$:把节点$u$到$v$路径上的所有点的权值乘以$x$: $2\ u\ v\ x$:把节点$u$到$v$路径上的所有点的权值加上 ...
- 2018ICPC网络赛(焦作站)K题题解
一.题目链接 https://nanti.jisuanke.com/t/31720 二.题意 给$N$种船只,第$i$种船的载重量是$V_i$,数量是$2^{C_i}-1$.接下来有$Q$次询问,每次 ...
- 2018ICPC网络赛(徐州站)A题题解
一.题目链接 https://nanti.jisuanke.com/t/31453 二.题意 给定$N$个位置,$2^k$种颜色,让你去涂色,条件是相邻的两种颜色类型异或值的二进制表示不全为$1$(以 ...
- 2019南昌网络赛I:Yukino With Subinterval(CDQ) (树状数组套主席树)
题意:询问区间有多少个连续的段,而且这段的颜色在[L,R]才算贡献,每段贡献是1. 有单点修改和区间查询. 思路:46min交了第一发树套树,T了. 稍加优化多交几次就过了. 不难想到,除了L这个点, ...
- 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 ...
- 南昌邀请赛网络赛 D.Match Stick Game(dp)
南昌邀请赛网络赛 D.Match Stick Game 题目传送门 题目就会给你一个长度为n的字符串,其中\(1<n<100\).这个字符串是一个表达式,只有加减运算符,然后输入的每一个字 ...
- 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 ...
随机推荐
- Summary of OAuth 2.0
Summary of OAuth 2.0 1 Problems: This pattern of applications obtaining user passwords obviously has ...
- python3正则表达式详细用法示例
转载自:https://www.runoob.com/python3/python3-reg-expressions.html
- Centos 7 忘记密码的情况下,修改root密码
应用场景 linux管理员忘记root密码,需要进行找回操作. 注意事项:本文基于centos7.4环境进行操作,由于centos的版本是有差异的,继续之前请确定好版本 操作步骤 一.重启系统,在开机 ...
- [转帖]判断Linux进程在哪个CPU核运行的方法
判断Linux进程在哪个CPU核运行的方法 原文网址:http://www.embeddedlinux.org.cn/html/xinshourumen/201601/30-5013.html 问 ...
- MySQL慢查询—开启慢查询
###一.简介 开启慢查询日志,可以让MySQL记录下查询超过指定时间的语句,通过定位分析性能的瓶颈,才能更好的优化数据库系统的性能. ###二.参数说明 slow_query_log 慢查询开启状态 ...
- Redis(1.10)Redis主从复制下的哨兵模式
[0]哨兵 sentinel 的作用 其概念参考:Redis高可用(理论篇) 中的[2] [0.1]监控:监控主从是否正常 [0.2]通知:出现问题时,可以通知相关人员 [0.3]故障转移:自动主从切 ...
- Kafka主题体系架构-复制、故障转移和并行处理
本文讨论了Kafka主题的体系架构,讨论了如何将分区用于故障转移和并行处理. Kafka主题,日志和分区 Kafka将主题存储在日志中.主题日志分为多个分区.Kafka将日志的分区分布在多个服务器或磁 ...
- Javascript - BOM 对象
浏览器相关的对象.获取浏览器相关的信息,可以设置和修改浏览器属性. 0. web-app 版 TodoList 小程序 用以下内容可以自己手写一个 TodoList 小程序,再添加几行代码就可以用手机 ...
- PAT A1005 Spell It Right (20)
书中AC代码 #include <cstdio> #include <cstring> #include <iostream> char num[10][10] = ...
- spring 的工厂类
spring 的工厂类 1. 工厂类 BeanFactory 和 ApplicationContext 的区别. ApplicationContext 是 BeanFactory 的子接口,提供了比父 ...