cdcq

梦幻小鱼干

导航

【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就自己出来了,不能盲目死磕

 

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 int rd(){int z=0,mk=1;  char ch=getchar();
 8     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
 9     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
10     return z*mk;
11 }
12 struct nds{int mk,x,y,z,id,ans;}a[810000];  int atp=0;
13 int n,m;
14 int b[210000],c[210000];
15 nds q[810000];
16 int v[810000];
17 int ans[210000];
18 nds d[210000];
19 inline int lbt(int x){  return x&-x;}
20 void mdf(int x,int y){  for(;x<=n;x+=lbt(x))  v[x]+=y;}
21 int qry(int x){  int bwl=0;  for(;x;x-=lbt(x))  bwl+=v[x];  return bwl;}
22 void cdq(int x,int y,int l,int r){
23     if(x>=y)  return ;
24     if(l>r)  return ;
25     if(l==r){
26         for(int i=x;i<=y;++i){
27             if(!a[i].mk)  mdf(a[i].y,a[i].z);
28             else  a[i].ans+=qry(a[i].z)-qry(a[i].y-1);
29         }
30         for(int i=x;i<=y;++i)if(!a[i].mk)  mdf(a[i].y,-a[i].z);
31         return ;
32     }
33     int md=(l+r)>>1;
34     int cnt1=0;
35     for(int i=x;i<=y;++i){
36         if(a[i].x<=md)  ++cnt1;
37         if(!a[i].mk && a[i].x<=md)  mdf(a[i].y,a[i].z);
38         if(a[i].mk && a[i].x>md)  a[i].ans+=qry(a[i].z)-qry(a[i].y-1);
39     }
40     for(int i=x;i<=y;++i)if(!a[i].mk && a[i].x<=md)
41         mdf(a[i].y,-a[i].z);
42     int hd1=x,hd2=x+cnt1;
43     for(int i=x;i<=y;++i){
44         if(a[i].x<=md)  q[hd1++]=a[i];
45         else  q[hd2++]=a[i];
46     }
47     for(int i=x;i<=y;++i)  a[i]=q[i];
48     cdq(x,hd1-1,l,md),cdq(hd1,y,md+1,r);
49 }
50 void prvs(){
51     atp=0;
52     for(int i=1;i<=m;++i)  ans[i]=0;
53 }
54 int main(){
55     //freopen("ddd.in","r",stdin);
56     cin>>n>>m;
57     prvs();
58     for(int i=1;i<=n;++i)  c[i]=rd();
59     c[0]=0,c[n+1]=0;
60     for(int i=1;i<=n;++i){
61         if(c[i]!=c[i-1])  a[++atp]=(nds){0,i,c[i],1,-1,0};
62         b[i]=c[i];
63     }
64     int mk,l,r,ql,qr;
65     for(int i=1;i<=m;++i){
66         mk=rd();
67         if(mk==1){
68             l=rd(),r=rd();
69             d[i]=(nds){mk,l,r,0,0,i};
70             if(r==c[l])  continue;
71             if(c[l]!=c[l-1])  a[++atp]=(nds){0,l,c[l],-1,i,0};
72             if(r!=c[l-1])  a[++atp]=(nds){0,l,r,1,i,0};
73             if(l<n){
74                   if(r==c[l+1])  a[++atp]=(nds){0,l+1,c[l+1],-1,i,0};
75                 if(c[l]==c[l+1])  a[++atp]=(nds){0,l+1,c[l+1],1,i,0};
76             }
77             c[l]=r;
78             //d[i]=(nds){mk,l,r,0,0,i};  Attention!!!
79         }
80         else{
81             l=rd(),r=rd(),ql=rd(),qr=rd();
82             a[++atp]=(nds){1,r,ql,qr,i,0};
83             a[++atp]=(nds){-1,l,ql,qr,i,0};
84             d[i]=(nds){mk,l,r,ql,qr,i};
85         }
86     }
87     cdq(1,atp,1,n);
88     for(int i=1;i<=atp;++i)if(a[i].mk)  ans[a[i].id]+=a[i].mk*a[i].ans;
89     for(int i=1;i<=m;++i){
90         if(d[i].mk==1)  b[d[i].x]=d[i].y;
91         else  printf("%d\n",ans[i]+(b[d[i].x]>=d[i].z && b[d[i].x]<=d[i].id));
92     }
93     return 0;
94 }
View Code

 

posted on 2019-09-10 18:05  cdcq  阅读(319)  评论(0编辑  收藏  举报