1. 程式人生 > >[Luogu3527][POI2011]MET-Meteors

[Luogu3527][POI2011]MET-Meteors

簡單的 space 設置 poi || pre 多少 odi else

BZOJ權限題!提供洛谷鏈接!

sol

昨晚突發奇想去學了一下整體二分。
這道題應該算是整體二分的板子題吧。

整體二分

首先要求可離線,不然還是安心碼數據結構吧。
整體二分簡單的來講,就是時間復雜度可以承受一次二分答案卻無法承受每個詢問都二分答案時(比如說依次二分的復雜度是\(O(n\log{n})\),那麽\(Q\)次二分答案就是\(O(Qn\log{n})\)),我們把所有詢問一起二分答案。往往會使用一些諸如樹狀數組之類的輔助工具。

拿這道題來講

“每個國家最早多少次之後收集到指定數量的隕石?”
那麽就二分一個時間\(mid\),然後判斷前\(mid\)次之內是否達到了指定數量。
我們把所有國家放在一起做,每次二分出了\(mid\)

之後,模擬\(l\)\(mid\)這一段的隕石(當然是用樹狀數組統計啦),然後按照“是否已經達到指定數量”把所有國家分成兩份。已經完成了的國家向左遞歸(因為答案可能會更小),沒有完成的國家向右遞歸,同時指定數量\(p\)中減掉已收集的隕石數量即可。

code

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 300005;
#define ll long long
int gi()
{
    int x=0,w=1;char ch=getchar();
    while
((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } int n,m,k,p[N],st[N],ed[N],val[N],ans[N]; struct
nation{ll p;int id;}q[N],q1[N],q2[N]; vector<int>a[N]; ll c[N]; void modify(int k,int v){while (k<=m) c[k]+=v,k+=k&-k;} ll query(int k){ll s=0;while (k) s+=c[k],k-=k&-k;return s;} void update(int p,int f) { if (st[p]<=ed[p]) modify(st[p],val[p]*f),modify(ed[p]+1,-val[p]*f); else modify(1,val[p]*f),modify(ed[p]+1,-val[p]*f),modify(st[p],val[p]*f); } 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[q[i].id]=l; return; } int mid=l+r>>1; int t1=0,t2=0;ll temp; for (int i=l;i<=mid;i++) update(i,1); for (int i=L;i<=R;i++) { temp=0; for (int j=0,sz=a[q[i].id].size();j<sz;j++) temp+=query(a[q[i].id][j]); if (temp>=q[i].p) q1[++t1]=q[i]; else q[i].p-=temp,q2[++t2]=q[i]; } for (int i=l;i<=mid;i++) update(i,-1); for (int i=L,j=1;j<=t1;i++,j++) q[i]=q1[j]; for (int i=L+t1,j=1;j<=t2;i++,j++) q[i]=q2[j]; solve(L,L+t1-1,l,mid);solve(L+t1,R,mid+1,r); } int main() { n=gi();m=gi(); for (int i=1;i<=m;i++) a[gi()].push_back(i); for (int i=1;i<=n;i++) q[i]=(nation){gi(),i}; k=gi(); for (int i=1;i<=k;i++) st[i]=gi(),ed[i]=gi(),val[i]=gi(); ++k;st[k]=1;ed[k]=m;val[k]=1e9;//設置右哨兵保證所有國家都可以完成 solve(1,n,1,k); for (int i=1;i<=n;i++) if (ans[i]==k) puts("NIE"); else printf("%d\n",ans[i]); return 0; }

[Luogu3527][POI2011]MET-Meteors