當(dāng)前位置:
首頁 >
[bzoj2527][Poi2011]Meteors_整体二分_树状数组
發(fā)布時(shí)間:2025/7/14
34
豆豆
生活随笔
收集整理的這篇文章主要介紹了
[bzoj2527][Poi2011]Meteors_整体二分_树状数组
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
Meteors bzoj-2527 Poi-2011
題目大意:題目鏈接。
注釋:略。
想法:
首先答案可以離線,且具有單調(diào)性。
這里的單調(diào)性就是隨著時(shí)間的推移,每個(gè)國家收集的隕石數(shù)增加。
不難想到整體二分,對(duì)時(shí)間進(jìn)行二分。
但是有一個(gè)問題,就是一個(gè)國家出現(xiàn)了多次,這樣的話我們用鏈表把他們記錄到一起即可,二分的時(shí)候傳鏈頭。
這個(gè)題就是用樹狀數(shù)組+差分實(shí)現(xiàn)區(qū)間加。
先把$[l,mid]$的操作都用樹狀數(shù)組加上。然后枚舉當(dāng)前還沒有答案的國家:每一個(gè)都訪問整條鏈加一起跟自己需要的$k$判斷一下扔進(jìn)左區(qū)間還是右區(qū)間即可。
Code:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define mod 1000000000000000 #define N 300010 using namespace std; typedef long long ll; ll tree[N]; int n,m; struct Node {int x,y,val;}q[N]; int head[N],nxt[N]; int a[N],t[N],w[N],ans[N]; inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;} int rd() {int x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;} inline int lowbit(int x) {return x&(-x);} void update(int x,ll val) {for(int i=x;i<=m;i+=lowbit(i)) (tree[i]+=val)%=mod;} ll query(int x) {ll ans=0; for(int i=x;i>=1;i-=lowbit(i)) (ans+=tree[i])%=mod; return ans;} void solve(int x,int y,int l,int r) {if(x>y) return;if(l==r){for(int i=x;i<=y;i++) ans[a[i]]=l;return;}int mid=(l+r)>>1;for(int i=l;i<=mid;i++){if(q[i].x<=q[i].y) update(q[i].x,q[i].val),update(q[i].y+1,-q[i].val);else update(q[i].x,q[i].val),update(m+1,-q[i].val),update(1,q[i].val),update(q[i].y+1,-q[i].val);}int tl=x,tr=y;for(int i=x;i<=y;i++){if(!w[a[i]]) t[tl++]=a[i];else{ll c=0,vc=0;for(int j=head[a[i]];j;j=nxt[j]){c+=query(j);if(c>=mod) vc+=c/mod,c%=mod;else if(c<0) vc+=c/mod-1,c=(c%mod+mod)%mod;}if(vc||c>=w[a[i]]) t[tl++]=a[i];else w[a[i]]-=c,t[tr--]=a[i];}}for(int i=x;i<=y;i++) a[i]=t[i];for(int i=l;i<=mid;i++){if(q[i].x<=q[i].y) update(q[i].x,-q[i].val),update(q[i].y+1,q[i].val);else update(q[i].x,-q[i].val),update(m+1,q[i].val),update(1,-q[i].val),update(q[i].y+1,q[i].val);}solve(x,tr,l,mid); solve(tl,y,mid+1,r); } int main() {n=rd(),m=rd();for(int i=1;i<=m;i++){int x=rd();nxt[i]=head[x]; head[x]=i;}for(int i=1;i<=n;i++) w[i]=rd(),a[i]=i;int k=rd();for(int i=1;i<=k;i++) q[i].x=rd(),q[i].y=rd(),q[i].val=rd();solve(1,n,1,k+1);for(int i=1;i<=n;i++){if(ans[i]>=1&&ans[i]<=k) printf("%d\n",ans[i]);else puts("NIE");}return 0; }小結(jié):整體二分的裸題。我們發(fā)現(xiàn)整體二分都通常和樹狀數(shù)組一起搭配使用。
轉(zhuǎn)載于:https://www.cnblogs.com/ShuraK/p/10108065.html
總結(jié)
以上是生活随笔為你收集整理的[bzoj2527][Poi2011]Meteors_整体二分_树状数组的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P4324 [JSOI2016]扭动的回
- 下一篇: 集合嵌套存储和遍历元素的示例