数据水了

P4097 【模板】李超线段树 / [HEOI2013] Segment

D0000 @ 2024-07-15 22:20:06

众所周知,线段树单点修改时,如果 l==r 那么就不能往下递归了。但是在本题下放标记的过程中,如果你把类似于 if(l==r)return; 这样的语句删掉,仍然能 A。


by lin_ziran @ 2024-07-17 08:44:03

@D0000

请问你说的是这里被注释的一行代码吗:

#define ls id << 1
#define rs id << 1 | 1
void Change_Tag(int id, int l, int r, int s) {//s 是加入的线段编号
    int &t = tag[id];
    int mid = l + r >> 1;
    if (cmp(s, t, mid) == s) swap(s, t);
//  if (l == r) return;
    if (cmp(s, t, l) == s) Change_Tag(ls, l, mid, s);
    else if (cmp(s, t, r) == s) Change_Tag(rs, mid + 1, r, s);
}

我认为当 l 等于 r 时,不用加这一行,因为此时已经不会再向下递归了。

因为当 l 等于 r 时,mid 的值也与 l 和 r 相等,所以求 cmp(s, t, mid) 与求 cmp(s, t, l) 和求 cmp(s, t, r) 等价。

又因为 if (cmp(s, t, mid) == s) swap(s, t);,且 s != t,所以后面的 cmp(s, t, l)cmp(s, t, r) 的返回值应该都等于 t,不等于 s。

所以当 l 等于 r 时,不会再往下递归了。

(第一次回复,若有错误欢迎指出)


by D0000 @ 2024-07-17 13:55:33

可能是写法不同,我的代码有一段:

void push_down(seg zyh,int l,int r,int o){//printf("(%d,%d)",l,r);
    int mid=(l+r)>>1;
    if(jisuan(zyh,mid)>jisuan(sgt[o].tag,mid)||(jisuan(zyh,mid)==jisuan(sgt[o].tag,mid)&&sgt[o].tag.id>zyh.id)){//if(zyh.id==49)//printf("(%d,%d)",l,r);// 
        seg ddx=zyh;
        zyh=sgt[o].tag;
        sgt[o].tag=ddx;
    }
    if(jisuan(zyh,l)<jisuan(sgt[o].tag,l)&&jisuan(zyh,r)<jisuan(sgt[o].tag,r))return;
    if(l==r)return;
    if(jisuan(zyh,l)<jisuan(sgt[o].tag,l))push_down(zyh,mid+1,r,o*2+1);
    else push_down(zyh,l,mid,o*2);
}

if(l==r)return; 注释掉后,去交 这道题就会 RE 7个点,但是本题不会,说明下方标记时不会到最后一层。


by D0000 @ 2024-07-17 13:57:03

虽然不能因为一份 AC 代码中有问题说明数据有问题,但是这或许能说明数据中的线段不存在很多条覆盖相同区间的线段


by lin_ziran @ 2024-07-17 19:22:58

@D0000

你说的对,数据水了,if (l == r) return; 不能省略。

我的证明有问题,因为 s 与 t 可能会相等。

这是我 AC 的记录

这是我 RE 6个点的记录(注释了 if (l == r) return;

我还试着对拍了一下,发现确实会出错:


|