标签:
2016暑假多校联合---Rikka with Sequence (线段树)
题意: 三种操作,1、区间上加上一个数;
2、区间上所有数开根号向下取整;
3、区间求和;
思路: 对于记录区间的最大值和最小值,如果相等的话,那么只需要对一个数开根号,算出开根号前后的差值,这样区间开根号就变成了区间减去一个数了;
由于是开根,所以存在两个数刚开始差为1,加上某数再开根依旧是差1,这样维护相同数区间的就没用了
比如(2,3) +6-->(8,9)开根-->(2,3)如果全是这样的操作,即使维护相同的数,每次开根的复杂度都是O(N),不T才怪
这样只需要维护区间最大值最小值,当差1的时候,看看是否开根后还是差1,如果还是差1,那么对区间开根号相当于整个区间减去同一个数,
这样就可以变开根为减了
#include <iostream> #include <algorithm> #include <cstdio> #include <cmath> 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+5; 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]+=(long long)(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; }
2016暑假多校联合---Rikka with Sequence (线段树)
标签:
原文地址:http://www.cnblogs.com/chen9510/p/5765865.html