hdu 5828

维护区间和+最大最小值就行了.

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
using namespace std;
#define INF 99999999
#define ll long long
struct p{
  int l,r;
  ll lz,val,maxx,minn;
}tree[4*100010];
int read() {
    char c=getchar();
    int re=0,f=1;
    while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') {re=re*10+c-'0';c=getchar();}
    return re*f;
}
void buildtree(int i,int l,int r)
{
  tree[i].l=l;tree[i].r =r;tree[i].minn=INF;
  tree[i].lz=0;
  if (l==r) {
      tree[i].val=read();
      tree[i].maxx=tree[i].minn=tree[i].val;
      return;
  }
  int mid=(l+r)/2;
  buildtree(i*2,l,mid);
  buildtree(i*2+1,mid+1,r);
  tree[i].maxx=max(tree[i*2].maxx,tree[i*2+1].maxx);
  tree[i].minn=min(tree[i*2].minn,tree[i*2+1].minn);
  tree[i].val=tree[i*2].val+tree[i*2+1].val;
}
void  updata(int i,int l,int r,ll d)
{
  if (tree[i].r==r&&tree[i].l==l)
  {
    tree[i].lz+=d;
    tree[i].val+=(r-l+1)*d;
    tree[i].maxx+=d;
    tree[i].minn+=d;
    return;
  }
   int mid=(tree[i].l+tree[i].r)/2;
   if (tree[i].lz)
  {
      tree[i*2].lz+=tree[i].lz;
      tree[i*2+1].lz+=tree[i].lz;
      tree[i*2].maxx+=tree[i].lz;
      tree[i*2+1].maxx+=tree[i].lz;
      tree[i*2].minn+=tree[i].lz;
      tree[i*2+1].minn+=tree[i].lz;
      tree[i*2].val+=(mid-tree[i].l+1)*tree[i].lz;
      tree[i*2+1].val+=(tree[i].r-mid)*tree[i].lz;
      tree[i].lz=0;
  }
  if (r<=mid) {updata(i*2,l,r,d);}
  if (l>mid) {updata(i*2+1,l,r,d);}
  if (l<=mid&&r>mid){updata(i*2,l,mid,d);updata(i*2+1,mid+1,r,d);}
  tree[i].val=tree[i*2].val+tree[i*2+1].val;
  tree[i].maxx=max(tree[i*2].maxx,tree[i*2+1].maxx);
  tree[i].minn=min(tree[i*2].minn,tree[i*2+1].minn);
}
ll find_val(int i,int l,int r)
{
  if (tree[i].l==l&&tree[i].r==r)
  {
    return tree[i].val;
  }
  int mid=(tree[i].l+tree[i].r)/2;
  if (tree[i].lz)
  {
      tree[i*2].lz+=tree[i].lz;
      tree[i*2+1].lz+=tree[i].lz;
      tree[i*2].maxx+=tree[i].lz;
      tree[i*2+1].maxx+=tree[i].lz;
      tree[i*2].minn+=tree[i].lz;
      tree[i*2+1].minn+=tree[i].lz;
      tree[i*2].val+=(mid-tree[i].l+1)*tree[i].lz;
      tree[i*2+1].val+=(tree[i].r-mid)*tree[i].lz;
      tree[i].lz=0;
  }

  if (r<=mid) return find_val(i*2,l,r);
  if (l>mid)  return find_val(i*2+1,l,r);
  if (l<=mid&&r>mid) return find_val(i*2,l,mid)+find_val(i*2+1,mid+1,r);
}
void down(int i,int l,int r)
{
  if (tree[i].l==l&&tree[i].r==r)
  {
    if(tree[i].maxx==tree[i].minn)
    {
      ll t=tree[i].maxx-floor((sqrt(tree[i].maxx*1.0)));
      tree[i].lz-=t;
      tree[i].val-=t*(r-l+1);
      tree[i].maxx=tree[i].minn=tree[i].maxx-t;
      return;
    }
    if(tree[i].maxx-tree[i].minn==1)
    {

      ll t1=floor((sqrt(tree[i].maxx*1.0)));
      ll t2=floor((sqrt(tree[i].minn*1.0)));
      ll t=tree[i].maxx-t1;
      if (t1-t2==1)
      {
        tree[i].lz-=t;
        tree[i].val-=t*(r-l+1);
        tree[i].maxx=t1;
        tree[i].minn=t2;
        return;
      }

    }
  }
  int mid=(tree[i].l+tree[i].r)/2;
  if (tree[i].lz)
  {
      tree[i*2].lz+=tree[i].lz;
      tree[i*2+1].lz+=tree[i].lz;
      tree[i*2].maxx+=tree[i].lz;
      tree[i*2+1].maxx+=tree[i].lz;
      tree[i*2].minn+=tree[i].lz;
      tree[i*2+1].minn+=tree[i].lz;
      tree[i*2].val+=(mid-tree[i].l+1)*tree[i].lz;
      tree[i*2+1].val+=(tree[i].r-mid)*tree[i].lz;
      tree[i].lz=0;
  }
  if (r<=mid) down(i*2,l,r);
  if (l>mid)  down(i*2+1,l,r);
  if (l<=mid&&r>mid) {down(i*2,l,mid);down(i*2+1,mid+1,r);}
  tree[i].val=tree[i*2].val+tree[i*2+1].val;
  tree[i].maxx=max(tree[i*2].maxx,tree[i*2+1].maxx);
  tree[i].minn=min(tree[i*2].minn,tree[i*2+1].minn);
}
int main()
{
  int T;
  scanf("%d",&T);
  while (T--)
  {
     int n,m;
     n=read();
     m=read();
     buildtree(1,1,n);
     for (int i=0;i<m;i++)
     {
       int opr,l,r;
       opr=read();
       l=read();
       r=read();
       if (opr==1){
          int v;
          v=read();
          updata(1,l,r,v);
       }
       if (opr==2)
       {
         down(1,l,r);
       }
       if (opr==3)
       {
         printf("%I64d\n",find_val(1,l,r));
       }
     }
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值