vijos1782——借教室(noip2012)
来源:互联网 发布:苹果还是外星人 程序员 编辑:程序博客网 时间:2024/06/10 06:12
这题有两种方法:线段树(90分)和二分(100分)
一、线段树
正常想到线段树,节点维护最小值。重要的是标记下放,只要有更新节点就有下放标记,可以把更新写在pushdown操作中。具体参照代码看。
#include<iostream>#include<algorithm>#include<cstdio>using namespace std;const int maxn=1000005;int x,ql,qr,pos;long long minv[maxn*4],decv[maxn*4]={0};void add(int o,int l,int r) //相当于建树咯{ if(l==r) minv[o]=x; else { int mid=l+(r-l)/2; if(pos<=mid) add(o*2,l,mid); if(pos>mid) add(o*2+1,mid+1,r); minv[o]=min(minv[o*2],minv[o*2+1]); }}void pushdown(int o) //标记下放兼更新minv{ minv[o]-=decv[o]; decv[o*2]+=decv[o]; decv[o*2+1]+=decv[o]; decv[o]=0;}void update(int o,int l,int r){ if(ql<=l&&qr>=r) { decv[o]+=x; pushdown(o); } else { pushdown(o); int mid=l+(r-l)/2; if(ql<=mid) update(o*2,l,mid); else pushdown(o*2); if(qr>mid) update(o*2+1,mid+1,r); else pushdown(o*2+1); //标记下放后,递归到的区间会更新minv,而没递归到的也要更新,两个else不可少。 minv[o]=min(minv[o*2],minv[o*2+1]); }}int get() //读入优化{ char c; do c=getchar(); while (c<'0'||c>'9'); int x=c-'0'; while ('0'<=(c=getchar())&&c<='9') x=x*10+c-'0'; return x; } int main(){ int n,m; scanf("%d%d",&n,&m); for(pos=1;pos<=n;pos++) { x=get(); add(1,1,n); } for(int i=1;i<=m;i++) { x=get(); ql=get(); qr=get(); update(1,1,n); if(minv[1]<0) { cout<<-1<<endl<<i<<endl; exit(0); } } cout<<0<<endl;}
不加读入优化T了5个点,加了T两个。
尽管不是满分算法,也可以来练习线段树打标记。codevs上读入优化后的可以过。
二、二分法
因为是闭区间,可以二分答案。比较每天需要的教室数和拥有的。用记头尾的方法更新所需教室数。具体见代码。
#include<cstdio>#include<cstring>using namespace std;const int maxn=1000006;int m,n,sum[maxn],d[maxn],s[maxn],j[maxn],a[maxn]={0};int get() //读入优化{ char ch; do ch=getchar(); while(ch<'0'||ch>'9'); int x=ch-'0'; while('0'<=(ch=getchar())&&ch<='9') x=x*10+ch-'0'; return x;}int check(int k) //判断是否可以到第k天{ memset(sum,0,sizeof(sum)); for(int i=1;i<=k;i++) { sum[s[i]]+=d[i]; //在头处标记 sum[j[i]+1]-=d[i]; //在尾处去标记 } int tot=0; for(int i=1;i<=n;i++) { tot+=sum[i]; if(tot>a[i]) return 0; //比较当前所需和拥有数 } return 1;}int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { a[i]=get(); } for(int i=1;i<=m;i++) { d[i]=get(); s[i]=get(); j[i]=get(); } int l=1,r=m; int mid,ans=0; while(l<=r) { mid=(l+r)>>1; if(!check(mid)) { ans=mid; r=mid-1; } else l=mid+1; } if(!ans) printf("0\n"); else printf("-1\n%d\n",ans);}
读入优化是无聊加的,反正可以过。
0 0
- vijos1782——借教室(noip2012)
- vijos1782借教室
- NOIP2012 借教室 (线段树)
- noip2012 借教室
- NOIP2012 借教室
- NOIP2012 借教室
- NOIP2012 借教室
- NOIp2012 借教室
- 1266. [NOIP2012] 借教室
- NOIP2012 借教室(classroom)
- noip2012借教室
- NOIP2012 借教室【二分】
- NOIP2012 借教室
- 【NOIP2012】codevs1217 借教室
- [NOIP2012] 借教室
- 【NOIP2012】借教室
- 【Noip2012】借教室
- [Noip2012]借教室
- 文章标题
- 线程与进程的区别
- hdu5655-BestCoder Round #78 (div.2)
- 黑苹果实战安装经历
- 开发板的烧录
- vijos1782——借教室(noip2012)
- 程序开发圣经
- [个人博客搬运]Method Swizzling的简单应用场景
- KEIL MAP文件分析
- 用递归和非递归的形式实现二叉树的前中后序遍历
- 1069. The Black Hole of Numbers (20)
- 解决QMediaPlayer没有声音的问题
- 【NOIP模拟】计数
- VC6命令行编译DLL