9 16 模拟赛&关于线段树上二分总结

1 考试时又犯了一个致命的错误,没有去思考T2的正解而是去简单的推了一下式子开始了漫漫找规律之路,不应该这样做的 为了得到规律虽然也打了暴力 但是还是打了一些不必要的程序 例如求组合数什么的比较浪费时间了。

考试后在我看来这都是浪费时间了 浪费了我足足1h30min 其实是可以避免的 得不到正解先去看下一道题 都做完了再回来重新审视这道题。

2 T3的正解推得的时间虽然不长但是没有仔细思考自己的做法是否优秀尽管应该是正确的 但是不充足的思考让我的代码变得非常的冗长。

例如 一些区间求和的操作我完全可以直接拿处理好的前缀和后缀和数组求但是我还是写了两个线段树函数求和。明明可以不用线段树O(n)来写代码复杂度会低的很但是我没有充分的思考直接码上了线段树...

当然还是有优点的 T1写完后直接开始对拍了 这一点很好(拍了2万组数据 所以我就没怎么检查 就直接交了。

再论述题解的时候 我希望这套题不仅仅是对考试的思考 还有对线段树的总结我想我应该总结线段树的某些功能是怎么写的了不能每次写的时候都再推一遍。

线段树上二分是一个技巧且比较有用因为其利用本身就是区间二分的形式建的树和本身就支持查询区间最值的特点致使我们寻找某个值比较方便。

这里先给出题目背景 给定一个序列对于询问 x 求整个序列小于x的第一个位置是谁?

这个我们暴力扫其实都可以 但是多次询问呢?把询问离线由大到小的搞,强制在线呢?一个比较经典的做法是 ST+二分 看似序列并不是单调的 但是我们二分这个答案的长度 加以ST表寻找最值即可解决。

带上单点修改呢?ST表可是不支持修改的,那么此时线段树上二分就可以轻易解决这个问题了。

考虑我们先进入线段树 观察总体是否都大于x 不是的话那就 再观察左边 然后 去左边还是去右边递归的搞即可。

限定区间l r 怎么搞 这就是思维和代码难度的升级了 其实我们发现这个东西并不好写 但是 这也是对线段树的 利用 尽管非常的困。

其实对于这一个询问来说 我们可以定点l 寻找 一个rr 属于r即可。但是显然的是限定这个r是没有什么意义的我们完全可以向左找到在和r比 所以这里r 是没有用的。这里放上代码 不断还是在区间二分即可。

具体的还是找到了两个端点相当于一个区间 然后复杂度还是logn;

code:

inline int ask(int p,int l,int r,int L,int x)//求 L R里第一个<=x的数字
{
    if(sum(p)<=x)return r;
    if(l==r)return l-1;
    int mid=(l+r)>>1;
    if(l>=L)
    {
        if(sum(l(p))<=x)return ask(r(p),mid+1,r,L,x);
        return ask(l(p),l,mid,L,x);
    }
    if(L>mid)return ask(r(p),mid+1,r,L,x);
    int w=ask(l(p),l,mid,L,x);
    if(w==mid)
    {
        if(sum(r(p))<=x)return r;
        return ask(r(p),mid+1,r,L,x);
    }
    return w;
}

这就是常用的板子 写出来要对线段树有一定的理解 复杂度 logn 可以发现我们其实是先找到了左端点 再寻找到右端点了 所以相当于找到了一个区间。
不算很复杂 当然找全局的答案就更显得轻松了。值得注意的是由于查找的是<=x 所以我们sum记录的是区间最大值。

猜你喜欢

转载自www.cnblogs.com/chdy/p/11531364.html