评分:省选/NOI-,难度:普及+/提高
这题真的和RMQ没有半点关系,只需要一个裸的线段树,连pushdown都不需要,只需要两种操作:区间修改和区间求最小值,在回溯时加上标记即可,唯一有点思维含量的是对环的处理,如果左端点大于了右端点,就维护(l,n)(1,r),否则正常维护即可,不知道线段树怎么打的可以看我的博客:线段树
下面给出参考代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 struct node 6 { 7 long long l,r,w,tag; 8 }tree[800005]; 9 long long n,m,q,x,y,k,ans; 10 void build(long long l,long long r,long long k) 11 { 12 tree[k].l=l;tree[k].r=r; 13 if(l==r) 14 { 15 scanf("%lld",&tree[k].w); 16 return; 17 } 18 long long mid=(l+r)/2; 19 build(l,mid,k*2); 20 build(mid+1,r,k*2+1); 21 tree[k].w=min(tree[k*2].w,tree[k*2+1].w); 22 } 23 void add(long long k,long long w,long long ll,long long rr) 24 { 25 long long l=tree[k].l,r=tree[k].r; 26 if(l>=ll&&r<=rr) 27 { 28 tree[k].tag+=w; 29 return; 30 } 31 //cout<<k<<" "<<l<<" "<<r<<endl; 32 long long mid=(l+r)/2; 33 //cout<<x<<" "<<y<<endl; 34 if(ll<=mid)add(k*2,w,ll,rr); 35 if(rr>mid)add(k*2+1,w,ll,rr); 36 tree[k].w=min(tree[k*2].w+tree[k*2].tag,tree[k*2+1].w+tree[k*2+1].tag); 37 return; 38 } 39 long long query(long long k,long long ll,long long rr) 40 { 41 if(tree[k].l>=ll&&tree[k].r<=rr) 42 { 43 return tree[k].w+tree[k].tag; 44 } 45 if(tree[k].l>rr||tree[k].r<ll) 46 { 47 return 213704440000; 48 } 49 long long mid=(tree[k].l+tree[k].r)/2,lc,rc; 50 lc=query(k*2,ll,rr); 51 rc=query(k*2+1,ll,rr); 52 return min(lc,rc)+tree[k].tag; 53 } 54 int main() 55 { 56 cin>>n; 57 build(1,n,1); 58 cin>>m; 59 for(long long i=1;i<=m;i++) 60 { 61 cin>>x>>y; 62 x++;y++; 63 char c=getchar(); 64 if(c==' ') 65 { 66 //4 1 67 ans=213744040000; 68 if(x>y)cout<<min(query(1,x,n),query(1,1,y)); 69 else cout<<query(1,x,y); 70 cout<<endl; 71 } 72 else 73 { 74 cin>>q; 75 if(x>y)add(1,q,x,n),add(1,q,1,y); 76 else add(1,q,x,y); 77 } 78 } 79 return 0; 80 }