【GDOI2013模拟1】屏保

Description

平面直角坐标系内有n个点,第i个点的坐标为(i,Hi),顺次连接这n个点。
现在给出一条直线y=h,求这条直线以下的由这条直线和其他线段围成的图形的面积。
兹瓷单点修改。
n<=10^5,hi<=1000

语文不好,放图来讲讲道理。
左边这张图的答案是3.75,右图为6.
这里写图片描述

Solution

考虑hi和hi+1所连的线段。
hi<h<hi+1 ,那么答案是 (hhi)22(hi+1hi)
这是个二次多项式。那么我们可以用树状数组维护当h=x时的每一项的系数。
hi+1<=h ,那么答案是 hhi+1hi2 。只有一次项和常数项,同样可以做。
具体用树状数组的实现,因为当 h[hi,hi+1] 的时候,它所形成的答案的多项式的系数都是一样的,那么就用树状数组的“区间加法”就好了。
剩余的同理。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 100005
#define H 1005
using namespace std;
typedef double db;
db t[3][H];
int n,m,x,y,h[N];
char ch[1];
void add(int z,int x,db y) {
    for(x++;x<=H-4;x+=x&-x) t[z][x]+=y;
}
db find(int z,int x) {
    db ans=0;
    for(x++;x;x-=x&-x) ans+=t[z][x];
    return ans;
}
void calc(int x,int y,int f) {
    if (x>y) swap(x,y);
    if (x!=y) {
        db p=1.0*f/(2*(y-x));
        add(0,x,p);add(0,y+1,-p);
        p=-2.0*x*f/(2*(y-x));
        add(1,x,p);add(1,y+1,-p);
        p=x*x*f*1.0/(2*(y-x));
        add(2,x,p);add(2,y+1,-p);
    }
    add(1,y+1,f);add(2,y+1,-f*(x+y)*1.0/2);
}
int main() {
    scanf("%d%d",&n,&m);
    fo(i,1,n) scanf("%d",&h[i]);
    fo(i,1,n-1) calc(h[i],h[i+1],1);
    for(;m;m--) {
        scanf("%s%d",ch,&x);
        if (ch[0]=='Q') {
            db a=find(0,x),b=find(1,x),c=find(2,x);
            printf("%.3lf\n",a*x*x+b*x+c);
        } else {
            scanf("%d",&y);x++;
            if (x>1) calc(h[x-1],h[x],-1),calc(h[x-1],y,1);
            if (x<n) calc(h[x],h[x+1],-1),calc(y,h[x+1],1);
            h[x]=y;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值