BZOJ2957 樓房重建

BZOJ2957 樓房重建

題目大意

給定二維平面中的垂直於x 軸正半軸的線段,求與原點(0,0) 連線中不與任何線段相交的線條條數

思路

線段樹維護
cnt[rt]rt 所表示的線段[l,r] 中可見的線段條數
sum[rt]rt 表示的線段[l,r] 中最大的斜率
對於當前修改的線段,其左邊的原先保存的答案依然可行
對於其右邊的線段,劃分成左右子區間,如果左子區間的最大斜率比更新值要小,直接統計右端點答案,否則統計左子區間的答案,再加上右子區間的答案,注意右子區間的答案爲cnt[rt]cnt[rt<<1] (因爲要加上左子區間的約束條件)

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;


const int MAXN = 100000+10;

double sum[MAXN<<2];
LL cnt[MAXN<<2],n,m,x,y;


LL calc(int rt,int l,int r,double h)
{
    if(l==r)    return sum[rt]>h;
    int mid=(l+r)>>1;
    if(sum[rt<<1]<=h)   return calc(rt<<1|1,mid+1,r,h);
    return calc(rt<<1,l,mid,rt)+cnt[rt]-cnt[rt<<1];
}


void updata(double val,int x,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=val;
        cnt[rt]=1;
        return ;
    }
    int mid=(l+r)>>1;
    if(x<=mid)  updata(val,x,l,mid,rt<<1);
    else updata(val,x,mid+1,r,rt<<1|1);
    sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
    cnt[rt]=cnt[rt<<1]+calc(rt<<1|1,mid+1,r,sum[rt<<1]);
}

int main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%lld%lld",&x,&y);
        updata( (double)y/x,x,1,n,1 );
        printf("%lld\n",cnt[1]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章