URAL 1977 Energy Wall(成段更新)

题意:有N(N<10^9)个点,P(P<10^5)个操作,每一秒过后,所以的数都会加上一个值T,每个操作前都有操作的时间,初始的时间是0,操作有两种类型,(1)"save l r",表示求区间[L,R]之间的所以数的和,并加到tot里,然后把[L,R]清空为零,(2)"enforce i d",表示点i-d+1和点i+d-1加上值X,点 i-d+2和点i+d-2加上值2*X……并且,最后所有数加上的X的和等于tot,这个操作之后,tot清零。

可知,操作(2)的话,可以看成加上两个等差数列,一个递增一个递减,对于每过一段时间就会所有数就会增加值,也可以表示成加上等差数列。需要注意的时,因为点的数目为10^9,所以要对操作的点离散化,比如有10个点,离散化之后有1、2、7、10。当操作的区间是[2,7]时,中间还有3,4,5,6,这几个数,所以在线段树的每个区间都要加一个值,表示将区间分割之后,中间的数的值和(比如1、2、7、10,分割成区间[1,2]和[7,10],增加一个变量extra表示中间3、4、5、6。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <map>

using namespace std;

typedef long long LL;

#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
#define MID(a,b) (a+((b-a)>>1))

const int N=4e5+5;

int n,m,p;

bool type[N/4];
int idx[N/4],K1[N/4],K2[N/4];

bool flag[N*4];
double l_add[N*4],r_add[N*4],extra[N*4];
double delta[N*4],sum[N*4];

vector<int> SY;
map<int,int> H;

struct Segtree
{
    double calc(int mid,double add,double valu)
    {
        int len=(SY[mid+1]-SY[mid])-1;
        if(len>0)
        {
            double add1=add+valu;
            double add2=add+(len)*valu;
            return (add1+add2)*len/2;
        }
        return 0;
    }
    void fun_add(double add1,double add2,double valu,int len,int ind)
    {
        sum[ind]+=(add1+add2)*len/2;
        l_add[ind]+=add1; r_add[ind]+=add2;
        delta[ind]+=valu;
    }
    void fun_zero(int ind)
    {
        sum[ind]=extra[ind]=0;
        flag[ind]=1;

        l_add[ind]=r_add[ind]=delta[ind]=0;
    }
    void PushDown(int lft,int rht,int ind)
    {
        int mid=MID(lft,rht);
        if(flag[ind])
        {
            fun_zero(LL(ind));
            fun_zero(RR(ind));
            flag[ind]=0;
        }
        if(l_add[ind]||r_add[ind])
        {
            double tmp1=l_add[ind]+(SY[mid]-SY[lft])*delta[ind];
            double tmp2=tmp1+(SY[mid+1]-SY[mid])*delta[ind];

            int len1=SY[mid]-SY[lft]+1;
            int len2=SY[rht]-SY[mid+1]+1;

            fun_add(l_add[ind],tmp1,delta[ind],len1,LL(ind));
            fun_add(tmp2,r_add[ind],delta[ind],len2,RR(ind));

            extra[ind]+=calc(mid,tmp1,delta[ind]);

            l_add[ind]=r_add[ind]=delta[ind]=0;
        }
    }
    void PushUp(int ind)
    {
        sum[ind]=sum[LL(ind)]+sum[RR(ind)]+extra[ind];
    }
    void build(int lft,int rht,int ind)
    {
        flag[ind]=0;
        l_add[ind]=r_add[ind]=extra[ind]=0;
        delta[ind]=sum[ind]=0;
        if(lft!=rht)
        {
            int mid=MID(lft,rht);
            build(lft,mid,LL(ind));
            build(mid+1,rht,RR(ind));
        }
    }
    void updata(int st,int ed,double add1,double add2,double valu,int lft,int rht,int ind)
    {
        if(st<=lft&&rht<=ed) fun_add(add1,add2,valu,SY[rht]-SY[lft]+1,ind);
        else
        {
            int mid=MID(lft,rht);

            PushDown(lft,rht,ind);
            if(ed<=mid) updata(st,ed,add1,add2,valu,lft,mid,LL(ind));
            else if(st>mid) updata(st,ed,add1,add2,valu,mid+1,rht,RR(ind));
            else
            {
                double tmp1=add1+(SY[mid]-SY[st])*valu;
                double tmp2=tmp1+(SY[mid+1]-SY[mid])*valu;
                updata(st,mid,add1,tmp1,valu,lft,mid,LL(ind));
                updata(mid+1,ed,tmp2,add2,valu,mid+1,rht,RR(ind));

                extra[ind]+=calc(mid,tmp1,valu);
            }
            PushUp(ind);
        }
    }
    void setZero(int st,int ed,int lft,int rht,int ind)
    {
        if(st<=lft&&rht<=ed)
        {
            //cout<<"setZero: lft="<<lft<<" rht="<<rht<<endl;
            fun_zero(ind);
        }
        else
        {
            int mid=MID(lft,rht);

            PushDown(lft,rht,ind);
            if(ed<=mid) setZero(st,ed,lft,mid,LL(ind));
            else if(st>mid) setZero(st,ed,mid+1,rht,RR(ind));
            else
            {
                extra[ind]=0;
                setZero(st,ed,lft,mid,LL(ind));
                setZero(st,ed,mid+1,rht,RR(ind));
            }
            PushUp(ind);
        }
    }
    double query(int st,int ed,int lft,int rht,int ind)
    {
        if(st<=lft&&rht<=ed)
        {
            return sum[ind];
        }
        else
        {
            int mid=MID(lft,rht);

            PushDown(lft,rht,ind);
            double ans;
            if(ed<=mid) ans=query(st,ed,lft,mid,LL(ind));
            else if(st>mid) ans=query(st,ed,mid+1,rht,RR(ind));
            else
            {
                double sum1=query(st,ed,lft,mid,LL(ind));
                double sum2=query(st,ed,mid+1,rht,RR(ind));
                ans=sum1+sum2+extra[ind];
            }
            PushUp(ind);
            return ans;
        }
    }
}seg;

int main()
{
    //freopen("in.txt","r",stdin);

    while(scanf("%d%d%d",&n,&p,&m)!=EOF)
    {
        SY.clear(); H.clear();

        for(int i=0;i<m;i++)
        {
            char op[10];
            scanf("%d%s%d%d",&idx[i],op,&K1[i],&K2[i]);
            if(op[0]=='s')
            {
                type[i]=0;
                SY.push_back(K1[i]);
                SY.push_back(K2[i]);
            }
            else
            {
                type[i]=1;
                SY.push_back(K1[i]+K2[i]-1);
                SY.push_back(K1[i]-K2[i]+1);
                SY.push_back(K1[i]);
                SY.push_back(K1[i]+1);
            }
        }

        sort(SY.begin(),SY.end());
        SY.erase(unique(SY.begin(),SY.end()),SY.end());

        int len=(int)SY.size();
        for(int i=0;i<len;i++) H[SY[i]]=i;

        //for(int i=0;i<len;i++) cout<<SY[i]<<" ";cout<<endl;

        double tot=0; int pre=0;
        seg.build(0,len-1,1);
        for(int i=0;i<m;i++)
        {
            double tmp=(idx[i]-pre)*1.0*p;
            seg.updata(0,len-1,tmp,tmp,0,0,len-1,1);
            pre=idx[i];

            if(type[i]==0)
            {
                int st=H[K1[i]],ed=H[K2[i]];
                tot+=seg.query(st,ed,0,len-1,1);

                //printf("check: %.6f\n",seg.query(st,ed,0,len-1,1));

                seg.setZero(st,ed,0,len-1,1);

                printf("%.10f\n",tot);
            }
            else
            {
                int st1=H[ K1[i]-K2[i]+1 ];
                int ed1=H[ K1[i] ];
                int st2=H[ K1[i]+1 ];
                int ed2=H[ K1[i]+K2[i]-1 ];

                double delta=tot/((LL)K2[i]*K2[i]);

                if(tot==0) continue;

                double tmp=delta*K2[i];
                seg.updata(st1,ed1,delta,tmp,delta,0,len-1,1);
                if(K2[i]!=1) seg.updata(st2,ed2,tmp-delta,delta,-delta,0,len-1,1);
                tot=0;
            }
        }
    }
    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值