1. 程式人生 > >Codeforces 567D - One-Dimensional Battle Ships - [樹狀數組+二分]

Codeforces 567D - One-Dimensional Battle Ships - [樹狀數組+二分]

兩個 http 屬於 現在 c++ += val 位置 dimen

題目鏈接:https://codeforces.com/problemset/problem/567/D

題意:

在一個 $1 \times n$ 的網格上,初始擺放著 $k$ 只船,每只船的長度均為 $a$ 個格子,已知所有船之間均不重疊、不觸碰。

現在Bob每次詢問Alice第 $i$ 個格子上是否存在船,Alice每次都會說不存在,求在第幾次詢問時,可以確定Alice撒謊了。

題解:

對於某次詢問一個位置 $x$ 是否有船,假設其屬於某個最小的區間 $(l,r)$,其中 $l,r$ 分別是曾經詢問過的位置。我們用樹狀數組配合二分 $O(\log^2 n)$ 尋找出 $l,r$。

那麽,可以計算出,$(l,r)$ 區間曾經最多能停放多少船只,而現在變成了兩個區間 $(l,x)$ 和 $(x,r)$ 後,又能停放多少船只。

這樣一來,最開始我們計算出整個區域 $(0,n+1)$ 最多放多少船只 $cur$,進而對每次計算都能計算出減少了多少船只,即 $cur$ 會減去一個數,直到某一次詢問,使得 $cur<k$,即代表Alice撒謊了。

AC代碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int n,k,a,m;

struct _BIT
{
    
int N,C[maxn]; #define lowbit(x) (x&(-x)) void init(int n) //初始化共有n個點 { N=n; for(int i=1;i<=N;i++) C[i]=0; } void add(int pos,int val) //在pos點加上val { while(pos<=N) { C[pos]+=val; pos+=lowbit(pos); } }
int ask(int pos) //查詢1~pos點的和 { int ret=0; while(pos>0) { ret+=C[pos]; pos-=lowbit(pos); } return ret; } }BIT; int lower(int x) { int l=1, r=BIT.N; while(l<r) { int mid=(l+r)>>1; if(BIT.ask(mid)<x) l=mid+1; else r=mid; } return l; } int upper(int x) { int l=1, r=BIT.N; while(l<r) { int mid=(l+r)>>1; if(BIT.ask(mid)<=x) l=mid+1; else r=mid; } return l; } int main() { cin>>n>>k>>a>>m; BIT.init(n+2); BIT.add(1,1), BIT.add(n+2,1); int cur=(n+1)/(a+1); for(int i=1,x;i<=m;i++) { scanf("%d",&x), x++; int tp=BIT.ask(x); int l=lower(tp), r=upper(tp); int old=(r-l)/(a+1); int now=(r-x)/(a+1)+(x-l)/(a+1); cur-=old-now; if(cur<k) { printf("%d\n",i); return 0; } BIT.add(x,1); } printf("-1\n"); }

Codeforces 567D - One-Dimensional Battle Ships - [樹狀數組+二分]