[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!
随机推荐
- python-字典和json
Python的字典和JSON在表现形式上非常相似 #这是Python中的一个字典 dic = { 'str': 'this is a string', 'list': [1, 2, 'a', 'b'] ...
- 数学建模--matlab基础知识
虽然python也能做数据分析,不过参加数学建模,咱还是用专业的 1. Matlab-入门篇:Hello world! 程序员入门第一式: disp(‘hello world!’) 2. 基本运算 先 ...
- linux命令学习笔记(16):which命令
我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索: which 查看可执行文件的位置. whereis 查看文件的位置. locate 配合数据库查看文件位置. f ...
- 优秀开源项目之一:视频监控系统iSpy
iSpy是一个开源的视频监控软件,目前已经支持中文.自己用了一下,感觉还是很好用的.翻译了一下它的介绍. iSpy将PC变成一个完整的安全和监控系统 iSpy使用您的摄像头和麦克风来检测和记录声音或运 ...
- bootstrap 左右框多项选择示例
bootstrap 左右选择框,左边框是未选项,右边框是已选择项,提供单选,全选按钮,以及取消已选项,如图示:
- java基础回顾之IO
Java的IO 是Java运用重要部分之一,涉及到的内容也比较多,容易混淆,一段时间不用,可能就会遗忘,要时常回顾记忆一下: (图片来源于网络) Java 流在处理上分为字符流和字节流. 字符流处理的 ...
- 【LeetCode】036. Valid Sudoku
题目: Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku board could ...
- Oracle 12c 多租户配置和修改 CDB 和 PDB 参数
1. 配置CDB 实例参数,影响CDB与所有 PDB为CDB配置例程参数相对于对于非CDB的数据库是变化不太.ALTER SYSTEM命令用于设置初始化参数,与使用ALTER DATABASE命令修改 ...
- IPC的使用
IPC,Inter-Processor Communication是SYS/BIOS处理核间通信的组件: IPC的几种应用方式: 1.最小使用(Minimal use) 这种情况是通过核间的通知机制( ...
- 【转】 Pro Android学习笔记(六六):安全和权限(3):Provider权限
目录(?)[-] 访问其他应用的content provider Provider的读写权限 Provider的URI权限 Provider的granting 全局granting 部分URI的gra ...