首页 > 代码库 > 洛谷P1083 借教室 二分 + 差分
洛谷P1083 借教室 二分 + 差分
洛谷P1083 借教室
二分 + 差分(或说前缀和,其实前缀和更准确一点)
首先二分答案,即取 mid 个人,且他们不会冲突
然后O(n) 判断是否冲突
如何判断呢,首先我们发现 一个人的操作相当于是将 一些连续的山削去了一个高度
然后我们可以记录这座山被消了多少高度,但这样一次就要 O(N) 总共(n^2)
但是我们发现高度差只有两个地方变了,一个是起始,一个是终止
t[ i ] 表示 h[ i ] - h[ i-1 ]
改变过后 于是 t[ s ]-=d,t[ t+1 ]+=d ;
然后这样修改只要改两个地方
查询就这样一直加上去
话说树状数组 的 区间修改 单点修改也用到了这种思想 区间修改只改两个点
然后就可以O(n) 判断是否符合条件了
最后输出l+1 如果 l==m 表示 全部都可以选 输出 0
时间复杂度 O(nlogn)
话说还有一种方法
因为每次 差分数组又要重新计算 ,然而其实不用上次算mid 这次算 x
若mid < x 则直接加上这一部分的差分
如果 x<mid 就对这一段的 逆运算
这样
如果不算最后还是要 O(n) 遍历一下看下是否冲突 高度小于 0
这一部分计算其实是均摊 O(n) 的 , 这样就做到了 O(logn + n)的做法
但因为还有 O(n) 所以只优化了 300ms
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <iostream> 8 #include <iomanip> 9 #define ll long long 10 using namespace std ; 11 12 const int maxn = 1000011 ; 13 const ll inf = 1e15 ; 14 ll n,m,l,r,mid ; // 15 ll d[maxn],a[maxn],sum[maxn] ; 16 int s[maxn],t[maxn] ; 17 18 inline ll read() 19 { 20 char ch = getchar() ; 21 ll x = 0, f = 1 ; 22 while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) ch = getchar() ; ch = getchar() ; } 23 while(ch>=‘0‘&&ch<=‘9‘) { x = x*10+ch-48 ; ch = getchar() ; } 24 return x*f ; 25 } 26 27 inline bool check( int mid ) 28 { 29 for(int i=1;i<=n;i++) sum[ i ] = 0 ; 30 for(int i=1;i<=mid;i++) 31 sum[ s[ i ] ]-=d[ i ] ,sum[ t[ i ]+1 ]+=d[ i ] ; 32 int x = 0 ; 33 for(int i=1;i<=n;i++) 34 { 35 x+=sum[ i ] ; 36 if( a[ i ] + x < 0 ) return false ; 37 } 38 return true ; 39 } 40 41 int main() 42 { 43 n = read() ; m = read() ; 44 for(int i=1;i<=n;i++) a[ i ] = read() ; 45 for(int i=1;i<=m;i++) 46 d[ i ] = read(),s[ i ] = read(),t[ i ] = read() ; 47 l = 0 ; 48 r = m ; 49 while( l < r ) 50 { 51 mid = (l+r+1)>>1 ; 52 if(check(mid)) 53 l = mid ; 54 else 55 r = mid-1 ; 56 } 57 if(l!=m) 58 printf("-1\n%lld\n",l+1) ; 59 else 60 printf("0\n") ; 61 return 0 ; 62 }
洛谷P1083 借教室 二分 + 差分
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。