【BZOJ2527】【POI2011】Meteors [整体二分]
2017-02-23 11:29
399 查看
Meteors
Time Limit: 60 Sec Memory Limit: 128 MB[Submit][Status][Discuss]
Description
这个星球经常会下陨石雨。BIU已经预测了接下来K场陨石雨的情况。
BIU的第i个成员国希望能够收集Pi单位的陨石样本。你的任务是判断对于每个国家,它需要在第几次陨石雨之后,才能收集足够的陨石。
Input
第一行是两个数N,M。
第二行有M个数,第i个数Oi表示第i段轨道上有第Oi个国家的太空站。
第三行有N个数,第i个数Pi表示第i个国家希望收集的陨石数量。
第四行有一个数K,表示BIU预测了接下来的K场陨石雨。
接下来K行,每行有三个数Li,Ri,Ai,表示第K场陨石雨的发生地点在从Li顺时针到Ri的区间中(如果Li<=Ri,就是Li,Li+1,...,Ri,否则就是Ri,Ri+1,...,m-1,m,1,...,Li),向区间中的每个太空站提供Ai单位的陨石样本。
Output
输出N行。第i行的数Wi表示第i个国家在第Wi波陨石雨之后能够收集到足够的陨石样本。如果到第K波结束后仍然收集不到,输出NIE。
Sample Input
3 51 3 2 1 3
10 5 7
3
4 2 4
1 3 1
3 5 2
Sample Output
3NIE
1
HINT
1<=n,m,k<=3*10^5 , 1<=Ai,Pi<=10^9Main idea
每个国家有一个需要价值,一个国家可以控制多个点,定义国家已经获得的价值为每个控制点上的价值和,每次操作可以将一段区间上每个点都加上一个价值,问每个国家在第几个操作时达到了需要价值,若达不到则输出NIE。
Solution
我们先从二分层面去考虑,对于一个点来说,可以二分答案来求解,那么我们就可以利用整体二分。
整体二分,就是我们将所有的询问一起来做,然后二分操作区间L,R,执行L,MID的部分,
然后判断询问是否可行,如果可行,将这个询问放到左边区间,否则加上左边的价值再把这个询问放到右区间。然后继续递归操作区间。
对于这道题来说,由于一个国家可以控制多个点,我们用链表来存,然后用Bit来判断是否可行。
这样就解决了这道题\(≧▽≦)/。
Code
#include<iostream> #include<string> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<map> using namespace std; typedef long long s64; const int ONE=300005; const int INF=2147483640; int n,m,k; int x; int next[ONE],first[ONE],go[ONE],tot; int Ans[ONE]; struct power { int need; int id; }a[ONE],qL[ONE],qR[ONE]; struct opera { int l,r; int val; }oper[ONE]; int get() { int res=1,Q=1;char c; while( (c=getchar())<48 || c>57 ) if(c=='-')Q=-1; res=c-48; while( (c=getchar())>=48 && c<=57 ) res=res*10+c-48; return res*Q; } void Add(int u,int v) { next[++tot]=first[u]; first[u]=tot; go[tot]=v; } namespace Bit { struct power { s64 value; }Node[ONE]; int lowbit(int i) { return i&-i; } void Update(int R,int x) { for(int i=R;i<=m;i+=lowbit(i)) Node[i].value+=x; } s64 Query(int R) { s64 res=0; for(int i=R;i>=1;i-=lowbit(i)) res+=Node[i].value; return res; } } void Update(int l,int r,int val) { if(l>r) { Bit::Update(l,val); Bit::Update(m+1,-val); Bit::Update(1,val); Bit::Update(r+1,-val); } else { Bit::Update(l,val); Bit::Update(r+1,-val); } } void Solve(int l,int r,int L,int R)//l,r 询问;L,R 操作 { if(l>r) return; if(L==R) { for(int i=l;i<=r;i++) Ans[a[i].id] = L; return; } int M=(L+R)>>1; for(int i=L;i<=M;i++) Update(oper[i].l, oper[i].r, oper[i].val); int l_num=0,r_num=0; for(int i=l;i<=r;i++) //判断询问在哪个区间 { s64 sum=0; for(int e=first[a[i].id];e;e=next[e]) { sum+=Bit::Query(go[e]); if(sum>=a[i].need) break; } if(sum>=a[i].need) { qL[++l_num]=a[i]; } else { qR[++r_num]=a[i]; qR[r_num].need-=sum; } } int t=l; for(int i=1;i<=l_num;i++) a[t++]=qL[i]; for(int i=1;i<=r_num;i++) a[t++]=qR[i]; for(int i=L;i<=M;i++) Update(oper[i].l, oper[i].r, -oper[i].val); Solve(l,l+l_num-1,L,M); Solve(l+l_num,r,M+1,R); } int main() { n=get(); m=get(); for(int i=1;i<=m;i++) {x=get(); Add(x,i);} for(int i=1;i<=n;i++) { a[i].need=get(); a[i].id=i; } k=get(); for(int i=1;i<=k;i++) { oper[i].l=get(); oper[i].r=get(); oper[i].val=get(); } Solve(1,n,1,k+1); for(int i=1;i<=n;i++) { if(Ans[i] > k) printf("NIE"); else printf("%d",Ans[i]); printf("\n"); } }View Code
相关文章推荐
- 【BZOJ2527】[Poi2011]Meteors 整体二分
- bzoj 2527: [Poi2011]Meteors 整体二分
- BZOJ 2527 [Poi2011]Meteors [整体二分+线段树]
- BZOJ 2527: [Poi2011]Meteors 整体二分 树状数组
- 【整体二分+树状数组】BZOJ2527 [Poi2011]Meteors
- 【BZOJ2527】【POI2011】Meteors(整体二分)
- 【BZOJ】2527 [Poi2011]Meteors 整体二分+树状数组
- bzoj 2527: [Poi2011]Meteors (树状数组+整体二分)
- BZOJ 2527: [Poi2011]Meteors 整体二分
- bzoj 2527: [Poi2011]Meteors -- 整体二分
- BZOJ 2527: [Poi2011]Meteors [整体二分]
- BZOJ2527 [Poi2011]Meteors 【整体二分 + 树状数组】
- [BZOJ2527][POI2011]Meteors(整体二分)
- BZOJ 2527 [Poi2011]Meteors(整体二分)
- [整体二分+树状数组]BZOJ 2527——[Poi2011]Meteors
- 整体二分&CDQ分治:[BZOJ2527][POI2011] meteors [BZOJ3295][CQOI2011] 动态逆序对
- [BZOJ]2527 [POI2011] Meteors 整体二分
- bzoj2527[Poi2011]Meteors整体二分+线段树
- [BZOJ2527][Poi2011]Meteors(整体二分+bit)
- bzoj 2527 [Poi2011]Meteors 整体二分+树状数组