洛谷 P1083 [ NOIP 2012 ] 借教室 —— 线段树 / 二分差分数组
题目:https://www.luogu.org/problemnew/show/P1083
当初不会线段树的时候做这道题...对差分什么不太熟练,一直没A,放在那儿不管...
现在去看,线段树就直接秒了;
不过要注意一下基本的细节囧...
但本题 n 的范围比较微妙,正常线段树会 T 一个点(不过运气好也能过);
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int const maxn=1e6+,maxm=2e7+;
int n,m,a[maxn],mn[maxm],ls[maxm],rs[maxm],cnt=,lzy[maxm];//cnt=1!!
bool fl=;
void pushup(int x){mn[x]=min(mn[ls[x]],mn[rs[x]]);}
void pushdown(int x)
{
if(!lzy[x])return;
lzy[ls[x]]+=lzy[x]; lzy[rs[x]]+=lzy[x];
mn[ls[x]]+=lzy[x]; mn[rs[x]]+=lzy[x];
lzy[x]=;
}
void build(int x,int l,int r)
{
if(l==r){mn[x]=a[l]; return;}
int mid=((l+r)>>);
ls[x]=++cnt; build(ls[x],l,mid);
rs[x]=++cnt,build(rs[x],mid+,r);
pushup(x);
}
void update(int x,int l,int r,int L,int R,int val)
{
if(l>=L&&r<=R){mn[x]+=val; lzy[x]+=val; return;}
pushdown(x); int mid=((l+r)>>);
if(mid>=L)update(ls[x],l,mid,L,R,val);
if(mid<R)update(rs[x],mid+,r,L,R,val);
pushup(x);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
build(,,n);
for(int i=,s,t,r;i<=m;i++)
{
scanf("%d%d%d",&r,&s,&t);
if(fl)continue;
update(,,n,s,t,-r);
if(mn[]<){printf("-1\n%d\n",i); fl=;}
}
if(!fl)printf("0\n");
return ;
}
T #13
所以要加个标记永久化。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int const maxn=1e6+,maxm=2e7+;
int n,m,a[maxn],mn[maxm],ls[maxm],rs[maxm],cnt=,lzy[maxm];//cnt=1!!
bool fl=;
void pushup(int x){mn[x]=min(mn[ls[x]]+lzy[ls[x]],mn[rs[x]]+lzy[rs[x]]);}//+!
void build(int x,int l,int r)
{
if(l==r){mn[x]=a[l]; return;}
int mid=((l+r)>>);
ls[x]=++cnt; build(ls[x],l,mid);
rs[x]=++cnt,build(rs[x],mid+,r);
// pushup(x);
mn[x]=min(mn[ls[x]],mn[rs[x]]);//
}
void update(int x,int l,int r,int L,int R,int val)
{
if(l==L&&r==R){lzy[x]+=val; return;}
int mid=((l+r)>>);
if(mid<L)update(rs[x],mid+,r,L,R,val);
else if(mid>=R)update(ls[x],l,mid,L,R,val);
else update(ls[x],l,mid,L,mid,val),update(rs[x],mid+,r,mid+,R,val);
pushup(x);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
build(,,n);
for(int i=,s,t,r;i<=m;i++)
{
scanf("%d%d%d",&r,&s,&t);
if(fl)continue;
update(,,n,s,t,-r);
if(mn[]-lzy[]<){printf("-1\n%d\n",i); fl=;}
}
if(!fl)printf("0\n");
return ;
}
还有一种二分差分数组的做法,其实很暴力;
不是开两个差分数组每次 memcpy ,而是只开一个记录减少量和原数组比较,会快一点。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int const maxn=1e6+;
int n,m,s[maxn],t[maxn],c[maxn],r[maxn],d[maxn];
bool ck(int mid)
{
memset(c,,sizeof c);
for(int i=;i<=mid;i++)c[s[i]]+=r[i],c[t[i]+]-=r[i];
bool fl=; int tmp=;
for(int i=;i<=n;i++)
{
tmp+=c[i];
if(d[i]-tmp<){fl=; break;}
}
return fl;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=,x,pre=;i<=n;i++)scanf("%d",&d[i]);
for(int i=;i<=m;i++)scanf("%d%d%d",&r[i],&s[i],&t[i]);
int l=,r=m,ans=-;
while(l<=r)
{
int mid=((l+r)>>);
if(ck(mid))ans=mid,r=mid-;
else l=mid+;
}
if(ans==-)printf("0\n");
else printf("-1\n%d\n",ans);
return ;
}
洛谷 P1083 [ NOIP 2012 ] 借教室 —— 线段树 / 二分差分数组的更多相关文章
- 洛谷P4243/bzoj1558 [JSOI2009]等差数列(线段树维护差分+爆炸恶心的合并)
题面 首先感谢这篇题解,是思路来源 看到等差数列,就会想到差分,又有区间加,很容易想到线段树维护差分.再注意点细节,\(A\)操作完美解决 然后就是爆炸恶心的\(B\)操作,之前看一堆题解的解释都不怎 ...
- 【洛谷P1083】[NOIP2012]借教室
借教室 [题目描述] 在n天中每天有一个可以借出的教室数,有m个订单,每个订单从第l天到第r天要借用x个教室.问能否满足所有的订单,若不能,输出第一个不能满足的订单编号. 思路: 1.1 ≤ n,m ...
- 题解【洛谷P1083】[NOIP2012]借教室
题面 二分到哪一个申请人要修改订单,可以差分\(+\)前缀和达到\(\Theta(n)\)的\(\text{check}\). 具体细节见代码. #include <bits/stdc++.h& ...
- 洛谷P1438 无聊的数列 (线段树+差分)
变了个花样,在l~r区间加上一个等差数列,等差数列的显著特点就是公差d,我们容易想到用线段树维护差分数组,在l位置加上k,在l+1~r位置加上d,最后在r+1位置减去k+(l-r)*d,这样就是在差分 ...
- NOIP 2012 借教室
洛谷 P1083 借教室 https://www.luogu.org/problem/P1083 JDOJ 1783: [NOIP2012]借教室 D2 T2 https://neooj.com/ol ...
- noip 2012 借教室 (线段树 二分)
/* 维护区间最小值 数据不超int 相反如果long long的话会有一组数据超时 无视掉 ll int */ #include<iostream> #include<cstdio ...
- noip 借教室 线段树95分做法
大致的思路是用线段树维护每个区间内部的最小值 段更新最小值 每次查某个区间的最小值是否满足租借要求 满足就借出去 update最小值 注意pushdown操作 还有一个从子区间提取答案的操作 提交地 ...
- NOIP2012借教室[线段树|离线 差分 二分答案]
题目描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要 向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借教室的信息,我们自 ...
- 洛谷P3434 [POI2006]KRA-The Disks(线段树)
洛谷题目传送门 \(O(n)\)的正解算法对我这个小蒟蒻真的还有点思维难度.洛谷题解里都讲得很好. 考试的时候一看到300000就直接去想各种带log的做法了,反正不怕T...... 我永远只会有最直 ...
随机推荐
- spring思想分析
摘要: EveryBody in the world should learn how to program a computer...because it teaches you how to th ...
- jenkins自动部署测试环境
构建脚本如下: echo "当前目录":$(pwd)echo "当前时间":$(date +%Y-%m-%d_%H:%M)find ./ -type f -na ...
- springmvc学习及源码地址
http://jinnianshilongnian.iteye.com/blog/1634096
- Luogu P1692 部落卫队
解题思路 数据范围不是很大,那应该不是那些普遍的图论的算法.考虑搜索,用暴力解决.从1到N枚举每一个点的位置,搜索这个点事选还是不选.如果在这个点之前选到的点中又和他冲突的点,那就不选,要么就选. 附 ...
- Luogu P1297 [国家集训队]单选错位
P1297 [国家集训队]单选错位 题目背景 原 <网线切割>请前往P1577 题目描述 gx和lc去参加noip初赛,其中有一种题型叫单项选择题,顾名思义,只有一个选项是正确答案.试卷上 ...
- [USACO06JAN] 冗余路径 Redundant Paths
题目描述 In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1. ...
- Java第九周总结
- mac下用crontab实现pytho3脚本自动定期执行,包括scrapy的定期执行
呃 其实要明天上午才能知道是否成功,毕竟改了一个小参数的. 首先,来学两个小命令: step1: $ sudo crontab -e step2: # 然后提示password输入密码,即可进入编辑页 ...
- IDLE in Python (Ubuntu)
To lauch IDLE in the Current Woking Directory >>> usr/bin/idle3 Alt + n # next command Alt ...
- 洛谷 2055 BZOJ 1433 [ZJOI2009]假期的宿舍
[题解] 既然是一人对应一床,那么显然可以用二分图匹配来做.俩人认识的话,如果其中一个a是在校学生,另一个b不回家,b就可以向a的床连边(a,b当然也可以是同一个人). 然后如果最大匹配数大于等于需要 ...