【GDOI模拟】屏保

Description

你最近安装了一个新的屏幕保护程序,如果你离开键盘5 分钟,屏保将会显

示一个有热带鱼的水族馆,水族馆的底端是由沙石形成的供鱼玩耍的地方,沙石

的高度可以设置,水位也可以设置。

水族馆可以看做是一个二维平面,宽看作N-1 列,最左端的横坐标为0,最

右端横坐标为N-1,每个整数横坐标都对应着一个沙石的高度H_i(0<=i<=N-1),

相邻横坐标i 和i+1 之间的沙石可以看做是由(i,H_i)和(i+1,H_i+1)这两个点形成

的线段。

如果水位为h,水覆盖着水族馆底端到y=h 这个区域,如果有部分沙石在水

面以上,这部分形成一个岛屿。

对于不同的沙石情况,你想知道被水覆盖区域的面积,即水位以下总面积减

去水中沙石的面积。

Solution

几何题?

开始以为这是一道几何题,然而只是一道代数几何题……
相邻的h之间都存在的一个梯形(或者没有),我们需要求当水漫到水位为x时,覆盖的面积。
怎么求?

分而治之

初中代数几何题做多了,看到这种题就想到了分类讨论。
假设x=h[i-1],y=h[i],如果x>y就调换。(因为要求的面积是正数)
1、如果当前的水位p≤x,那么覆盖的面积为0。
2、如果当前的水位x≤p≤y,那么覆盖的面积为(用一下三角形相似) p22px+x22(yx)
3、如果当前的水位y≤p,那么覆盖的面积为 pyx2+y

维护——树状数组

发现最多只是一元二次方程,而且只用求和运算,修改也只是单点修改,那么放到树状数组上面最方便了。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=200007;
int i,j,k,l,t,n,m,ans,h[maxn];
double ta[maxn],tb[maxn],tc[maxn],z;
char s[10];
int lowbit(int x){return x&(-x);}
void add(double *x,int y,double z){
    while(y<=1100){
        x[y]+=z;
        y+=lowbit(y);
    }
}
double get(double *x,int y){
    double u=0;
    while(y>0){
        u+=x[y];
        y-=lowbit(y);
    }
    return u;
} 
double chu(double x,double y){if(y==0)return 0;else return x/y;}
void change(int x,int y,int z){
    if(x>y)swap(x,y);
    add(ta,x+1,z*chu(1,(2*y-2*x)));
    add(tb,x+1,z*chu(-x,(y-x)));
    add(tc,x+1,z*chu(x*x,(2*y-2*x)));
    add(ta,y+1,(-1)*z*chu(1,(2*y-2*x)));
    add(tb,y+1,(-1)*z*chu(-x,(y-x)));
    add(tc,y+1,(-1)*z*chu(x*x,(2*y-2*x)));
    add(tb,y+1,1*z);
    add(tc,y+1,z*(chu((y-x),2)-y));
}
int main(){
    scanf("%d%d",&n,&m);
    fo(i,1,n)scanf("%d",&h[i]);
    fo(i,2,n){
        change(h[i-1],h[i],1);
    }
    fo(t,1,m){
        scanf("%s%d",s,&k);
        if(s[0]=='Q'){
            z=get(ta,k)*k*k+get(tb,k)*k+get(tc,k);
            printf("%.3f\n",z);
        }
        else{
            scanf("%d",&l);k++;
            if(k!=1)change(h[k],h[k-1],-1);
            if(k!=n)change(h[k],h[k+1],-1);
            h[k]=l;
            if(k!=1)change(h[k],h[k-1],1);
            if(k!=n)change(h[k],h[k+1],1);
        }
    }
}

你可能感兴趣的:(分治,树状数组,屏保,GDOI,代数几何题)