BZOJ 2957: 樓房重建

題目描述php

/*
思路很是巧妙的一道題 
不難看出線段樹維護的是區間內每一個點與原點連線的斜率的最大值 
考慮合併區間時怎麼合併答案 
左區間必定會被看到,右區間能被看到的必定大於左區間的最大值 
因此能夠查詢右區間中大於左區間最大值的數的個數來向上合併 
每次修改的複雜度爲log^2n 
*/
#include<complex>
#include<cstdio>
using namespace std;
const int N=1e5+7;
int n,m;
int Siz[N<<2];
double Max[N<<2];
int qread()
{
    int x=0;
    char ch=getchar();
    while(ch<'0' || ch>'9')ch=getchar();
    while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
int Calc(int l,int r,int rt,double v)
{
    if(Max[rt]<=v)return 0;
    if(l==r)return Max[rt]>v;
    int mid=l+r>>1;
    if(Max[rt<<1]<=v)return Calc(mid+1,r,rt<<1|1,v);
    return Calc(l,mid,rt<<1,v)+Siz[rt]-Siz[rt<<1];
}
void Modify(int l,int r,int rt,int p,double v)
{
    if(l==r)
    {
        Max[rt]=v;Siz[rt]=1;
        return;
    }
    int mid=l+r>>1;
    if(p<=mid)Modify(l,mid,rt<<1,p,v);
    else Modify(mid+1,r,rt<<1|1,p,v);
    Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
    Siz[rt]=Siz[rt<<1]+Calc(mid+1,r,rt<<1|1,Max[rt<<1]);
}
int main()
{
    scanf("%d%d",&n,&m);
    int x,y;
    while(m--)
    {
        x=qread();y=qread();
        Modify(1,n,1,x,1.0*y/x);
        printf("%d\n",Siz[1]);
    }
    return 0;
}
相關文章
相關標籤/搜索