[noi38]游戏
用线段数维护一段区间内的两个信息:1.需要多少经验就可以让有一个人升级,2.等级和。单点修改直接暴力做就可以,区间修改考虑如果这个区间不会产生升级就不递归下去而是打上懒标记。
考虑这个算法的时间复杂度:单点修改的时间复杂度为$o(log_{2}n)$,而区间修改由于每一个点最多升级n+q次,总时间复杂度为$o((n+q)log_{2}m)$,可以过。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1000001 4 #define L (k<<1) 5 #define R (L+1) 6 #define mid (l+r>>1) 7 int n,m,q,p,x,y,z,mi[N],f[N],lazy[N],a[N]; 8 void up(int k){ 9 f[k]=f[L]+f[R]; 10 mi[k]=min(mi[L],mi[R]); 11 } 12 void down(int k){ 13 lazy[L]+=lazy[k]; 14 mi[L]-=lazy[k]; 15 lazy[R]+=lazy[k]; 16 mi[R]-=lazy[k]; 17 lazy[k]=0; 18 } 19 void update(int k,int l,int r,int x,int y,int z){ 20 if ((l>y)||(x>r))return; 21 if ((x<=l)&&(r<=y)){ 22 mi[k]-=z; 23 if (mi[k]>0){ 24 lazy[k]+=z; 25 return; 26 } 27 if (l==r){ 28 mi[k]-=a[f[k]+1]; 29 f[k]=upper_bound(a+1,a+m+1,-mi[k])-a-1; 30 mi[k]+=a[f[k]+1]; 31 return; 32 } 33 } 34 down(k); 35 update(L,l,mid,x,y,z); 36 update(R,mid+1,r,x,y,z); 37 up(k); 38 } 39 void update(int k,int l,int r,int x,int y){ 40 if (l==r){ 41 f[k]=upper_bound(a+1,a+m+1,y)-a-1; 42 mi[k]=a[f[k]+1]-y; 43 return; 44 } 45 down(k); 46 if (x<=mid)update(L,l,mid,x,y); 47 else update(R,mid+1,r,x,y); 48 up(k); 49 } 50 int query(int k,int l,int r,int x,int y){ 51 if ((l>y)||(x>r))return 0; 52 if ((x<=l)&&(r<=y))return f[k]; 53 down(k); 54 return query(L,l,mid,x,y)+query(R,mid+1,r,x,y); 55 } 56 int main(){ 57 scanf("%d%d%d",&n,&m,&q); 58 for(int i=1;i<=m;i++)scanf("%d",&a[i]); 59 a[m+1]=0x3f3f3f3f; 60 for(int i=1;i<=n;i++){ 61 scanf("%d",&x); 62 update(1,1,n,i,x); 63 } 64 for(int i=1;i<=q;i++){ 65 scanf("%d%d%d",&p,&x,&y); 66 if (p==1){ 67 scanf("%d",&z); 68 update(1,1,n,x,y,z); 69 } 70 if (p==2)update(1,1,n,x,y); 71 if (p==3)printf("%d\n",query(1,1,n,x,y)); 72 } 73 }