[CodeChef] The Street
给定两个长度为n的数列A和B,开始数组A中每一项值为0,数组B中每一项值为负无穷大。接下来有m次操作:1.数组A区间加一个等差数列;2.数组B区间对一个等差数列取max;3.询问ai+bi的值。n<=1e9,m<=3e5。
这道题做了两天。。告诉我:要随着递归函数变的变量,千万不要放在全局。。
#include <cstdio>
using namespace std; //#bug2:LL
typedef long long LL;
const LL maxn=1e9+, maxm=3e5+;
const LL INF=1ll<<;
//#bug10:INF不够大
LL n, m, op, l2s, cnt;
LL u, v, a, b, x; //注意a,b是一直不变的
LL ll, rr;
//注意值最多可以加到LL外!
struct node{
LL b1, change1; //max
LL a1;
LL a2, b2; //add
LL lc, rc;
}seg[maxm**]; inline LL abs(LL x) { return x>?x:-x; }
inline LL max(LL x, LL y) { return x>y?x:y; } void flag(LL now, LL a1, LL b1, LL a2, LL b2);
//给孩子打上标记
void push_down(LL &now, LL l, LL r, LL a, LL b){
//#bug4:忘记新建结点
if (!now) now=++cnt, seg[now].a1=-INF;
//#bug5:历史遗留问题(话说这个pushdown有点多余)
//#bug7:b值有变化。。现在更新的b值不与下传的b值相同
//更新的是目前uvab,下传的是这个结点的ab。(在下面修正)
flag(now, seg[now].a1, seg[now].a1+(r-l)*seg[now].b1,
a, a+(r-l)*b);
}
//取max,当然是标记永久化!
void flag(LL now, LL a1, LL b1, LL a2, LL b2){
//有个新来的数列的公差b,是在外面的
//如果a1,b1没有值,或者盖住,那就直接赋值
//bug#6:a1没有值的时候应该是负无穷大
if (seg[now].a1==-INF||(a1<=a2&&b1<=b2)){
seg[now].a1=a2, seg[now].b1=b;
seg[now].change1=;
return;
}
if (a1>a2&&b1>b2) return;
//那么现在必定有区间内交点
LL mid=(ll+rr)>>;
LL nowl, nowr;
if (abs(a1-a2)<abs(b1-b2)){ //交点在左边
//如果a1右半部分更小,就全部赋值(#bug7:注意下传标记!)
if (a1>a2) {
LL tmp=b; b=seg[now].b1;
//它的孩子替换成自己
//bug#9:l和r不对
nowl=ll, nowr=rr; rr=mid;
push_down(seg[now].lc, ll, mid, seg[now].a1, seg[now].b1);
rr=nowr; ll=mid+;
push_down(seg[now].rc, mid+, rr,
seg[now].a1+(mid+-nowl)*seg[now].b1, seg[now].b1);
ll=nowl;
b=tmp;
seg[now].a1=a2, seg[now].b1=b, seg[now].change1=;
}
//反之,把新数列的左半边往下传(它的孩子替换成新的)
//#bug7:忽略了等于的情况(证伪)
if (a1<=a2) { //#bug8:b不对。就是原来的
nowr=rr; rr=mid;
push_down(seg[now].lc, ll, mid, a2, b);
rr=nowr;
}
} else {
//与之前相同(它的孩子替换成新的)
if (a1>=a2) { //同bug8
//#bug9:下面的式子还是要用原来的ll
nowl=ll; ll=mid+;
push_down(seg[now].rc, mid+, rr, a2+(mid+-nowl)*b, b);
ll=nowl;
}
//同bug7(证伪)
if (a1<a2) {
LL tmp=b; b=seg[now].b1;
//它的孩子替换成自己(注意下传标记!)
nowl=ll, nowr=rr; rr=mid;
push_down(seg[now].lc, ll, mid, seg[now].a1, seg[now].b1);
rr=nowr; ll=mid+;
push_down(seg[now].rc, mid+, rr,
seg[now].a1+(mid+-nowl)*seg[now].b1, seg[now].b1);
ll=nowl;
b=tmp;
seg[now].a1=a2, seg[now].b1=b, seg[now].change1=;
}
}
}
void modify1(LL &now, LL l, LL r){
if (!now) now=++cnt, seg[now].a1=-INF; //用引用新建结点,这样空的不会被识别
l2s=a+(l-u)*b; //l这个x坐标上的l2的值
ll=l, rr=r;
LL mid=(l+r)>>;
LL nowl, nowr;
//如果修改过,必须再这里先push一下,不然flag的时候,可能会覆盖
if (seg[now].change1){
LL tmp=b; b=seg[now].b1;
//它的孩子替换成自己
nowl=ll, nowr=rr; rr=mid;
push_down(seg[now].lc, l, mid, seg[now].a1, seg[now].b1);
rr=nowr, ll=mid+;
push_down(seg[now].rc, mid+, r,
seg[now].a1+(mid+-nowl)*seg[now].b1, seg[now].b1);
ll=nowl;
b=tmp;
//#bug3:mid+1全没加 (还是mid!!)
seg[now].change1=;
}
if (l>=u&&r<=v){
//给出俩直线开始结束,修改下传结点。只要判断交点位置
flag(now, seg[now].a1, seg[now].a1+(r-l)*seg[now].b1,
l2s, l2s+(r-l)*b);
return;
}
if (mid>=u) modify1(seg[now].lc, l, mid);
if (mid<v) modify1(seg[now].rc, mid+, r);
}
//这个。。可以差分
void modify2(LL &now, LL l, LL r){
if (!now) now=++cnt, seg[now].a1=-INF; //这样空的不会被识别
l2s=a+(l-u)*b;
if (l>=u&&r<=v){
seg[now].a2+=l2s, seg[now].b2+=b;
return;
}
LL mid=(l+r)>>;
if (mid>=u) modify2(seg[now].lc, l, mid);
if (mid<v) modify2(seg[now].rc, mid+, r);
}
LL q1(LL now, LL l, LL r){ //只有当路径上全部都是-INF时,这个东西不存在
if (!now) return -INF;
LL mid=(l+r)>>, v=seg[now].a1+(x-l)*seg[now].b1;
if (mid>=x) return max(v, q1(seg[now].lc, l, mid));
else return max(v, q1(seg[now].rc, mid+, r));
}
LL q2(LL now, LL l, LL r){ //差分。。
if (!now) return ;
LL mid=(l+r)>>, v=seg[now].a2+(x-l)*seg[now].b2;
if (mid>=x) return v+q2(seg[now].lc, l, mid); //bug#1,mid>x
else return v+q2(seg[now].rc, mid+, r);
} int main(){
scanf("%lld%lld", &n, &m);
LL root=++cnt; seg[root].a1=-INF;
for (LL i=; i<m; ++i){
scanf("%lld", &op);
//这里把a看成开始,b看成公差!
if (op<) {
scanf("%lld%lld%lld%lld", &u, &v, &a, &b);
LL t=a; a=b; b=t;
}
if (op==) modify1(root, , n);
if (op==) modify2(root, , n);
if (op==){
scanf("%lld", &x);
LL query1=q1(, , n), query2=q2(, , n);
if (query1==-INF) { printf("NA\n"); continue; }
printf("%lld\n", query1+query2);
}
}
return ;
}
[CodeChef] The Street的更多相关文章
- Codechef March Challenge 2014——The Street
The Street Problem Code: STREETTA https://www.codechef.com/problems/STREETTA Submit Tweet All submis ...
- AC日记——The Street codechef March challenge 2014
The Street 思路: 动态开节点线段树: 等差序列求和于取大,是两个独立的子问题: 所以,建两颗线段树分开维护: 求和:等差数列的首项和公差直接相加即可: 取大: 对于线段树每个节点储存一条斜 ...
- [CodeChef - STREETTA] The Street 李超线段树
大致题意: 给出两个序列A,B,A初始为负无穷,B初始为0,有三种操作 1.在A上区间[u,v]上加一个等差数列,取与原本A序列的最大值. 2.在B上区间[u,v]上加一个等差数列. 3.给出一个点X ...
- 【BZOJ-3514】Codechef MARCH14 GERALD07加强版 LinkCutTree + 主席树
3514: Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 1288 Solved: 490 ...
- 申请邓白氏编码的时候总是提示 Enter a valid Street Address 怎么办?
今天要申请一个苹果开发者公司(Company)账号,然后需要邓白氏编码,然后填写企业的基本信息.其中对于Street Address认真的对照着中文翻译为如下格式: Kang Hesheng buil ...
- ACM: 限时训练题解-Street Lamps-贪心-字符串【超水】
Street Lamps Bahosain is walking in a street of N blocks. Each block is either empty or has one la ...
- Codeforce - Street Lamps
Bahosain is walking in a street of N blocks. Each block is either empty or has one lamp. If there is ...
- 【BZOJ4260】 Codechef REBXOR 可持久化Trie
看到异或就去想前缀和(⊙o⊙) 这个就是正反做一遍最大异或和更新答案 最大异或就是很经典的可持久化Trie,从高到低贪心 WA: val&(1<<(base-1))得到的并不直接是 ...
- Wall Street English
1月23号,报名Wall Street English!
随机推荐
- SQL2005 2008配置错误,无法识别的配置节 system.serviceModel machine.config配置文件有问题
当装上2008的时候,你以前的程序突然报出你的machine.config配置文件有问题,比如 “/” 应用程序中的服务器错误. 配置错误 说明 : 在处理向该请求提供服务所需的配置文件时出错.请检查 ...
- Sed 命令详解 正则表达式元字符
1.简介 sed是非交互式的编辑器.它不会修改文件,除非使用shell重定向来保存结果.默认情况下,所有的输出行都被打印到屏幕上. sed编辑器逐行处理文件(或输入),并将结果发送到屏幕.具体过程如下 ...
- 大数据_学习_01_Hadoop 2.x及hbase常用端口及查看方法
二.参考资料 1.Hadoop 2.x常用端口及查看方法
- Java企业微信开发_08_素材管理之下载微信临时素材到本地服务器
一.本节要点 1.获取临时素材接口 请求方式:GET(HTTPS) 请求地址:https://qyapi.weixin.qq.com/cgi-bin/media/get?access_token=AC ...
- rabbitmq-交换机
四种交换机: direct fanout topic headers http://www.jianshu.com/p/469f4608ce5d
- 【二叉树的递归】03判断二叉树中有没有和为给定值的路径【Path Sum】
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 给定一个二叉树和一个和,判断这个树 ...
- Python 转义字符中没有这个 「\e」 !
问题来源于技术交流群里: 常见的转义字符 \n.\t 之类的我们都知道什么意思,但是这个 \e 是什么意思呢? 抱着一股钻研的精神,我搜了一把. 结果,所有的页面里都是只有一句简单的 \e 代表转义. ...
- tarjian求lca
看了好多dalao的博客,就总结一下啦ovo tarjian算法很是神奇,它的作用是求lca.它是一种离线算法. 在线是指输入一个询问输出一个结果. 离线是将询问一次性输入,一起处理. tarjan它 ...
- HLSL学习笔记(一):基础
http://www.cnblogs.com/rainstorm/archive/2013/05/04/3057444.html 前言 五一在家无事,于是学习了一下HLSL,基于XAN4.0的.学习完 ...
- iOS中的日历
iOS自带三种日历,公历.佛教日历和日本日历,要设置日历可以进入"设置-通用-语言与地区-日历"设置,我们中国使用的iPhone默认设置成公历.而泰国人使用的iPhone默认设置的 ...