HDU5828 Rikka with Sequence 线段树

分析:这个题和bc round 73应该是差不多的题,当时是zimpha巨出的,那个是取phi,这个是开根

吐槽:赛场上写的时候直接维护数值相同的区间,然后1A,结果赛后糖教一组数据给hack了,仰慕

        由于是开根,所以存在两个数刚开始差为1,加上某数再开根依旧是差1,这样维护相同数区间的就没用了

        比如(2,3) +6-->(8,9)开根-->(2,3)如果全是这样的操作,即使维护相同的数,每次开根的复杂度都是O(N),不T才怪

        这样只需要维护区间最大值最小值,当差1的时候,看看是否开根后还是差1,这样就可以变开根为减了

        加强数据后,1591ms。。。(还是太年轻)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <stdlib.h>
using namespace std;
typedef long long LL;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char Getchar() {
    if(head==tail) {
        int l=fread(buffer,1,BufferSize,stdin);
        tail=(head=buffer)+l;
    }
    return *head++;
}
inline int read() {
    int x=0,f=1;char c=Getchar();
    for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
    return x*f;
}
const int N=1e5+1;
LL sum[N<<2],lz[N<<2],mx[N<<2],mn[N<<2];
void up(int rt){
  sum[rt]=sum[rt<<1]+sum[rt<<1|1];
  mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
  mn[rt]=min(mn[rt<<1],mn[rt<<1|1]);
}
void build(int rt,int l,int r){
  lz[rt]=0;
  if(l==r){sum[rt]=read();mn[rt]=mx[rt]=sum[rt];return;}
  int mid=l+r>>1;
  build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
  up(rt);
}
void down(int rt,int l,int r){
  if(lz[rt]!=0){
    int mid=l+r>>1; 
    lz[rt<<1]+=lz[rt];
    lz[rt<<1|1]+=lz[rt];
    mn[rt<<1]+=lz[rt];
    mx[rt<<1]+=lz[rt];
    mx[rt<<1|1]+=lz[rt];
    mn[rt<<1|1]+=lz[rt];
    sum[rt<<1]+=lz[rt]*(mid-l+1);
    sum[rt<<1|1]+=lz[rt]*(r-mid);
    lz[rt]=0; 
  } 
}
int x,y,t,T,n,m;
void kaigen(int rt,int l,int r){
  if(x<=l&&r<=y){
     if(mx[rt]==mn[rt]){
        lz[rt]-=mx[rt];
        mx[rt]=sqrt(mx[rt]);
        mn[rt]=mx[rt];
        lz[rt]+=mx[rt];
        sum[rt]=mx[rt]*(r-l+1);
        return;
     }
     else if(mx[rt]==mn[rt]+1){
       LL x1=sqrt(mx[rt]);
       LL x2=sqrt(mn[rt]);
       if(x1==x2+1){
          lz[rt]-=(mx[rt]-x1);
          sum[rt]-=(mx[rt]-x1)*(r-l+1);
          mx[rt]=x1;mn[rt]=x2;
          return;
       } 
    } 
  }
  int mid=l+r>>1;down(rt,l,r);
  if(x<=mid)kaigen(rt<<1,l,mid);
  if(y>mid)kaigen(rt<<1|1,mid+1,r);
  up(rt);
}
void add(int rt,int l,int r){
  if(x<=l&&r<=y){
    lz[rt]+=t;
    sum[rt]+=1ll*(r-l+1)*t;
    mx[rt]+=t;mn[rt]+=t;
    return ;
  }
  int mid=l+r>>1;down(rt,l,r);
  if(x<=mid)add(rt<<1,l,mid);
  if(y>mid)add(rt<<1|1,mid+1,r);
  up(rt);
}
LL get(int rt,int l,int r){
  if(x<=l&&r<=y)return sum[rt];
  int mid=l+r>>1;down(rt,l,r);
  LL ret=0;
  if(x<=mid)ret+=get(rt<<1,l,mid);
  if(y>mid)ret+=get(rt<<1|1,mid+1,r);
  return ret;
}
int main(){
  T=read();
  while(T--){
    n=read();m=read();
    build(1,1,n);
    while(m--){
      int op;
      op=read();x=read();y=read();
      if(op==1){
        t=read();add(1,1,n);
      }
      else if(op==2)kaigen(1,1,n);
      else printf("%I64d\n",get(1,1,n));
    }
  }
  return 0;
}
View Code

 

posted @ 2016-08-12 15:12  shuguangzw  阅读(324)  评论(0编辑  收藏  举报