• [CodeChef] The Street


    给定两个长度为n的数列A和B,开始数组A中每一项值为0,数组B中每一项值为负无穷大。接下来有m次操作:1.数组A区间加一个等差数列;2.数组B区间对一个等差数列取max;3.询问ai+bi的值。n<=1e9,m<=3e5。

    这道题做了两天。。告诉我:要随着递归函数变的变量,千万不要放在全局。。

      1 #include <cstdio>
      2 using namespace std;
      3 
      4 //#bug2:LL
      5 typedef long long LL;
      6 const LL maxn=1e9+5, maxm=3e5+5;
      7 const LL INF=1ll<<62;
      8 //#bug10:INF不够大
      9 LL n, m, op, l2s, cnt;
     10 LL u, v, a, b, x; //注意a,b是一直不变的
     11 LL ll, rr;
     12 //注意值最多可以加到LL外!
     13 struct node{
     14     LL b1, change1; //max
     15     LL a1;
     16     LL a2, b2; //add
     17     LL lc, rc;
     18 }seg[maxm*31*2];
     19 
     20 inline LL abs(LL x) { return x>0?x:-x; }
     21 inline LL max(LL x, LL y) { return x>y?x:y; }
     22 
     23 void flag(LL now, LL a1, LL b1, LL a2, LL b2);
     24 //给孩子打上标记
     25 void push_down(LL &now, LL l, LL r, LL a, LL b){
     26     //#bug4:忘记新建结点
     27     if (!now) now=++cnt, seg[now].a1=-INF;
     28     //#bug5:历史遗留问题(话说这个pushdown有点多余)
     29     //#bug7:b值有变化。。现在更新的b值不与下传的b值相同
     30     //更新的是目前uvab,下传的是这个结点的ab。(在下面修正)
     31     flag(now, seg[now].a1, seg[now].a1+(r-l)*seg[now].b1,
     32          a, a+(r-l)*b);
     33 }
     34 //取max,当然是标记永久化!
     35 void flag(LL now, LL a1, LL b1, LL a2, LL b2){
     36     //有个新来的数列的公差b,是在外面的
     37     //如果a1,b1没有值,或者盖住,那就直接赋值
     38     //bug#6:a1没有值的时候应该是负无穷大
     39     if (seg[now].a1==-INF||(a1<=a2&&b1<=b2)){
     40         seg[now].a1=a2, seg[now].b1=b;
     41         seg[now].change1=1;
     42         return;
     43     }
     44     if (a1>a2&&b1>b2) return;
     45     //那么现在必定有区间内交点
     46     LL mid=(ll+rr)>>1;
     47     LL nowl, nowr;
     48     if (abs(a1-a2)<abs(b1-b2)){ //交点在左边
     49         //如果a1右半部分更小,就全部赋值(#bug7:注意下传标记!)
     50         if (a1>a2) {
     51             LL tmp=b; b=seg[now].b1;
     52             //它的孩子替换成自己
     53             //bug#9:l和r不对
     54             nowl=ll, nowr=rr; rr=mid;
     55             push_down(seg[now].lc, ll, mid, seg[now].a1, seg[now].b1);
     56             rr=nowr; ll=mid+1;
     57             push_down(seg[now].rc, mid+1, rr,
     58                       seg[now].a1+(mid+1-nowl)*seg[now].b1, seg[now].b1);
     59             ll=nowl;
     60             b=tmp;
     61             seg[now].a1=a2, seg[now].b1=b, seg[now].change1=1;
     62         }
     63         //反之,把新数列的左半边往下传(它的孩子替换成新的)
     64         //#bug7:忽略了等于的情况(证伪)
     65         if (a1<=a2) { //#bug8:b不对。就是原来的
     66             nowr=rr; rr=mid;
     67             push_down(seg[now].lc, ll, mid, a2, b);
     68             rr=nowr;
     69         }
     70     } else {
     71         //与之前相同(它的孩子替换成新的)
     72         if (a1>=a2) { //同bug8
     73             //#bug9:下面的式子还是要用原来的ll
     74             nowl=ll; ll=mid+1;
     75             push_down(seg[now].rc, mid+1, rr, a2+(mid+1-nowl)*b, b);
     76             ll=nowl;
     77         }
     78         //同bug7(证伪)
     79         if (a1<a2) {
     80             LL tmp=b; b=seg[now].b1;
     81             //它的孩子替换成自己(注意下传标记!)
     82             nowl=ll, nowr=rr; rr=mid;
     83             push_down(seg[now].lc, ll, mid, seg[now].a1, seg[now].b1);
     84             rr=nowr; ll=mid+1;
     85             push_down(seg[now].rc, mid+1, rr,
     86                       seg[now].a1+(mid+1-nowl)*seg[now].b1, seg[now].b1);
     87             ll=nowl;
     88             b=tmp;
     89             seg[now].a1=a2, seg[now].b1=b, seg[now].change1=1;
     90         }
     91     }
     92 }
     93 void modify1(LL &now, LL l, LL r){
     94     if (!now) now=++cnt, seg[now].a1=-INF; //用引用新建结点,这样空的不会被识别
     95     l2s=a+(l-u)*b; //l这个x坐标上的l2的值
     96     ll=l, rr=r;
     97     LL mid=(l+r)>>1;
     98     LL nowl, nowr;
     99     //如果修改过,必须再这里先push一下,不然flag的时候,可能会覆盖
    100     if (seg[now].change1){
    101         LL tmp=b; b=seg[now].b1;
    102         //它的孩子替换成自己
    103         nowl=ll, nowr=rr; rr=mid;
    104         push_down(seg[now].lc, l, mid, seg[now].a1, seg[now].b1);
    105         rr=nowr, ll=mid+1;
    106         push_down(seg[now].rc, mid+1, r,
    107                   seg[now].a1+(mid+1-nowl)*seg[now].b1, seg[now].b1);
    108         ll=nowl;
    109         b=tmp;
    110         //#bug3:mid+1全没加 (还是mid!!)
    111         seg[now].change1=0;
    112     }
    113     if (l>=u&&r<=v){
    114         //给出俩直线开始结束,修改下传结点。只要判断交点位置
    115         flag(now, seg[now].a1, seg[now].a1+(r-l)*seg[now].b1,
    116              l2s, l2s+(r-l)*b);
    117         return;
    118     }
    119     if (mid>=u) modify1(seg[now].lc, l, mid);
    120     if (mid<v) modify1(seg[now].rc, mid+1, r);
    121 }
    122 //这个。。可以差分
    123 void modify2(LL &now, LL l, LL r){
    124     if (!now) now=++cnt, seg[now].a1=-INF; //这样空的不会被识别
    125     l2s=a+(l-u)*b;
    126     if (l>=u&&r<=v){
    127         seg[now].a2+=l2s, seg[now].b2+=b;
    128         return;
    129     }
    130     LL mid=(l+r)>>1;
    131     if (mid>=u) modify2(seg[now].lc, l, mid);
    132     if (mid<v) modify2(seg[now].rc, mid+1, r);
    133 }
    134 LL q1(LL now, LL l, LL r){ //只有当路径上全部都是-INF时,这个东西不存在
    135     if (!now) return -INF;
    136     LL mid=(l+r)>>1, v=seg[now].a1+(x-l)*seg[now].b1;
    137     if (mid>=x) return max(v, q1(seg[now].lc, l, mid));
    138     else return max(v, q1(seg[now].rc, mid+1, r));
    139 }
    140 LL q2(LL now, LL l, LL r){ //差分。。
    141     if (!now) return 0;
    142     LL mid=(l+r)>>1, v=seg[now].a2+(x-l)*seg[now].b2;
    143     if (mid>=x) return v+q2(seg[now].lc, l, mid); //bug#1,mid>x
    144     else return v+q2(seg[now].rc, mid+1, r);
    145 }
    146 
    147 int main(){
    148     scanf("%lld%lld", &n, &m);
    149     LL root=++cnt; seg[root].a1=-INF;
    150     for (LL i=0; i<m; ++i){
    151         scanf("%lld", &op);
    152         //这里把a看成开始,b看成公差!
    153         if (op<3) {
    154             scanf("%lld%lld%lld%lld", &u, &v, &a, &b);
    155             LL t=a; a=b; b=t;
    156         }
    157         if (op==1) modify1(root, 1, n);
    158         if (op==2) modify2(root, 1, n);
    159         if (op==3){
    160             scanf("%lld", &x);
    161             LL query1=q1(1, 1, n), query2=q2(1, 1, n);
    162             if (query1==-INF) { printf("NA
    "); continue; }
    163             printf("%lld
    ", query1+query2);
    164         }
    165     }
    166     return 0;
    167 }
  • 相关阅读:
    cxgrid动态创建列
    cxgrid显示海量数据
    Delphi 两个应用程序(进程)之间的通信
    Delphi实现窗体内嵌其他应用程序窗体
    Change tab position of PageControl to bottom
    how can I make the login form transparent?
    UniDBGrid增加显示记录数的label及隐藏refresh按钮
    java工厂模式实例化class
    Java 语言细节
    applet示例 WelcomeApplet.java <Core Java>
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/7529935.html
Copyright © 2020-2023  润新知