屏保

来源:互联网 发布:淘宝店铺出售法律风险 编辑:程序博客网 时间:2024/04/27 21:09

题意:
一个有热带鱼的水族馆,水族馆的底端是由沙石形成的供鱼玩耍的地方,沙石的高度可以设置,水位也可以设置。水族馆可以看做是一个二维平面,宽看作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 这个区域,如果有部分沙石在水面以上,这部分形成一个岛屿。对于不同的沙石情况,你想知道被水覆盖区域的面积,即水位以下总面积减去水中沙石的面积。

N(3<=N<=100,000)
询问数M(1<=M<=100,000)
沙石高度H_i(0<=Hi<=1000)

分析:
设ans[h] 为 水面高度为h时水面下沙石的面积。
考虑两个相邻点组成的图形的面积对ans[h]的贡献,设它们的高度分别是X和Y。
hmin(x,y) 时,这个图形对ans[h]的贡献是一个一次函数。
2° min(x,y)< hmax(x,y) 时,这个图形对ans[h]的贡献是一个二次函数。
3°max(x,y) h时,这个图形对ans[h]的贡献是一个常数。
所以我们可以在ans[h]记录答案关于h的二次项系数、一次项系数、常数。用线段树上述三种情况进行区间修改。

#include <cstdio>#include <algorithm>using namespace std;typedef double Do;const int N = 1e5 + 10;int h[N];double pass[N / 100 * 4][3],ans[N][3];int n,m;void push(int tot,int l,int r) {    if (!pass[tot][0] && !pass[tot][1] && !pass[tot][2]) return;    if (l == r) {        for (int i = 0;i < 3;i ++) ans[l][i] += pass[tot][i];    }    else {        for (int i = 0;i < 3;i ++) {            pass[tot << 1][i] += pass[tot][i];            pass[tot << 1 | 1][i] += pass[tot][i];        }    }    for (int i = 0;i < 3;i ++) pass[tot][i] = 0;}void ins(int tot,int l,int r,int l1,int r1,Do a,Do b,Do c) {    if (l1 > r1) return;    if (l1 <= l && r1 >= r) {        pass[tot][2] += a;        pass[tot][1] += b;        pass[tot][0] += c;        push(tot,l,r);        return;    }    push(tot,l,r);    int mid = (l + r) >> 1;    if (l1 <= mid) ins(tot << 1,l,mid,l1,r1,a,b,c);    if (mid < r1) ins(tot << 1 | 1,mid + 1,r,l1,r1,a,b,c);}void add(int X,int Y,int t) {    double x = X,y = Y;    if (x > y) swap(x,y);    ins(1,1,1000,1,min(X,Y),0,t,0);    double z = y - x;    ins(1,1,1000,min(X,Y) + 1,max(X,Y),-t * 1 / (2 * z),t * y / z,t * (x + z / 2 - y * y / (2 * z)));    ins(1,1,1000,max(X,Y) + 1,1000,0,0,t * (x + y) / 2);}void get(int tot,int l,int r,int pos) {    push(tot,l,r);    if (l == r) return;    int mid = (l + r) >> 1;    if (pos <= mid) get(tot << 1,l,mid,pos);    else get(tot << 1 | 1,mid + 1,r,pos);}int main() {    scanf("%d%d",&n,&m);    for (int i = 1;i <= n;i ++) scanf("%d",&h[i]);    for (int i = 1;i < n;i ++) add(h[i],h[i + 1],1);    for (int i = 1;i <= m;i ++) {        char type;        scanf(" %c",&type);        if (type == 'Q') {            int H;            scanf("%d",&H);            Do Ans = (n - 1) * H;            H = min(H,1000);            get(1,1,1000,H);            Do cur = 0,x = 1;            for (int j = 0;j <= 2;j ++) {                cur += x * ans[H][j];                x *= H;            }                           printf("%.3lf\n",Ans - cur);        }        else {            int k,H;            scanf("%d%d",&k,&H);            k ++;            if (k < n) add(h[k],h[k + 1],-1),add(H,h[k + 1],1);            if (k > 1) add(h[k - 1],h[k],-1),add(h[k - 1],H,1);            h[k] = H;        }    }}
0 0
原创粉丝点击