sylvia 是一个热爱学习的女孩子,今天她想要学习数据结构技巧。
在看了一些博客学了一些姿势后,她想要找一些数据结构题来练练手。于是她的好朋友九条可怜酱给她出了一道题。
给出一个长度为 nn 的数列 AA,接下来有 mm 次操作,操作有三种:
- 对于所有的 i∈[li∈[l,r],将 AiAi 变成 Ai+xAi+x。
- 对于所有的 i∈[li∈[l,r],将 AiAi 变成 ⌊Ai‾‾√⌋⌊Ai⌋。
- 对于所有的 i∈[li∈[l,r],询问 AiAi 的和。
作为一个不怎么熟练的初学者,sylvia 想了好久都没做出来。而可怜酱又外出旅游去了,一时间联系不上。于是她决定向你寻求帮助:你能帮她解决这个问题吗。
输入格式
第一行两个数:n,mn,m。
接下来一行 nn 个数 AiAi。
接下来 mm 行中,第 ii 行第一个数 tti 表示操作类型:
若 tti=1,则接下来三个整数 lli,ri,xi,表示操作一。
若 tti=2,则接下来三个整数 lli,ri,表示操作二。
若 tti=3,则接下来三个整数 lli,ri,表示操作三。
输出格式
对于每个询问操作,输出一行表示答案。
样例一
input
5 5 1 2 3 4 5 1 3 5 2 2 1 4 3 2 4 2 3 5 3 1 5
output
5 6
题解:
线段树套路题,对于sqrt操作,十分的玄学,是这样做的:
1.加法和区间求和还是老套路
2.sqrt有如下几个讨论:
(1).对于整个区间的数全部相等,那么直接做区间减法即可
(2).对于区间中的最大值max,最小值min,如果min+1==max && sqrt(min)+1==sqrt(max) 也可以做区间减法
复杂度证明请参见论文
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #define ls (node<<1) 8 #define rs (node<<1|1) 9 using namespace std; 10 typedef long long ll; 11 const int N=100005; 12 struct node{ 13 ll max,min,mark,sum; 14 }t[N<<2]; 15 int gi(){ 16 int str=0;char ch=getchar(); 17 while(ch>'9' || ch<'0')ch=getchar(); 18 while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar(); 19 return str; 20 } 21 int n,m,a[N]; 22 void upd(int node){ 23 t[node].max=t[ls].max>t[rs].max?t[ls].max:t[rs].max; 24 t[node].min=t[ls].min<t[rs].min?t[ls].min:t[rs].min; 25 t[node].sum=t[ls].sum+t[rs].sum; 26 } 27 void build(int l,int r,int node){ 28 if(l==r){ 29 t[node].max=t[node].min=t[node].sum=a[l]; 30 return ; 31 } 32 int mid=(l+r)>>1; 33 build(l,mid,ls);build(mid+1,r,rs); 34 upd(node); 35 } 36 void pushdown(int node,int l,int r){ 37 if(!t[node].mark)return ; 38 ll k=t[node].mark; 39 t[ls].max+=k;t[ls].min+=k;t[rs].max+=k;t[rs].min+=k; 40 t[ls].mark+=k;t[rs].mark+=k; 41 int mid=(l+r)>>1; 42 t[ls].sum+=(ll)(mid-l+1)*k;t[rs].sum+=(ll)(r-mid)*k; 43 t[node].mark=0; 44 } 45 void updata(int l,int r,int node,int sa,int se,int to){ 46 if(l>se || r<sa)return ; 47 if(sa<=l && r<=se){ 48 t[node].max+=to;t[node].min+=to;t[node].mark+=to; 49 t[node].sum+=(ll)to*(r-l+1); 50 return ; 51 } 52 pushdown(node,l,r); 53 int mid=(l+r)>>1; 54 updata(l,mid,ls,sa,se,to);updata(mid+1,r,rs,sa,se,to); 55 upd(node); 56 } 57 void sqt(int l,int r,int node,int sa,int se){ 58 if(l>se || r<sa)return ; 59 if(sa<=l && r<=se){ 60 if(t[node].max==t[node].min){ 61 ll tmp=(ll)sqrt(t[node].max)-t[node].max; 62 t[node].sum+=(ll)tmp*(r-l+1);t[node].min+=tmp;t[node].max+=tmp;t[node].mark+=tmp; 63 return ; 64 } 65 ll q1=sqrt(t[node].max),q2=sqrt(t[node].min); 66 if(t[node].max==t[node].min+1 && q1==q2+1){ 67 t[node].sum+=(ll)(q1-t[node].max)*(r-l+1); 68 t[node].min+=q1-t[node].max;t[node].mark+=q1-t[node].max; 69 t[node].max+=q1-t[node].max; 70 return ; 71 } 72 } 73 pushdown(node,l,r); 74 int mid=(l+r)>>1; 75 sqt(l,mid,ls,sa,se);sqt(mid+1,r,rs,sa,se); 76 upd(node); 77 } 78 ll query(int l,int r,int node,int sa,int se){ 79 if(l>se || r<sa)return 0; 80 if(sa<=l && r<=se)return t[node].sum; 81 pushdown(node,l,r); 82 int mid=(l+r)>>1; 83 return query(l,mid,ls,sa,se)+query(mid+1,r,rs,sa,se); 84 } 85 void work() 86 { 87 n=gi();m=gi(); 88 for(int i=1;i<=n;i++)a[i]=gi(); 89 build(1,n,1); 90 int flag,x,y,z; 91 while(m--){ 92 flag=gi();x=gi();y=gi(); 93 if(flag==1){ 94 z=gi(); 95 updata(1,n,1,x,y,z); 96 } 97 else if(flag==2)sqt(1,n,1,x,y); 98 else if(flag==3)printf("%lld ",query(1,n,1,x,y)); 99 } 100 } 101 102 int main() 103 { 104 freopen("pp.in","r",stdin); 105 freopen("pp.out","w",stdout); 106 work(); 107 return 0; 108 }