体育课(line)问题描述:
又是一节体育课的时间了,有n个同学排成了一排。他们都很讨厌排在第一个位置的同学,于是后面的同学中比第一个高的都会产生一个高兴值,这个高兴值等于他的身高减去第一个同学的身高。当然比第一个同学矮的同学产生兴奋值为0。
现在体育老师来了,他拥有神奇的魔法,现在他能做如下的三件事:
1:询问某段区间高兴值最大的那个是多少。
2:把某两个同学交换一下位置。
3:选取一段区间的人,把第一个人身高加上t,第二个加上2t,第三个加上3t以此类推。
但是体育老师不会数数,于是他找到你了,对于每一个询问,他要你帮他求出那个值。
输入说明:
第一行两个整数n,m表示有n个人,有m个操作。
第二行n个整数,顺序输入每个人的身高。(身高<=10^8)
接下来m行,每行第一个数位一个type表示是做哪一件事情。
如果type=1,那么接下来有两个整数l,r,表示询问这段区间的最大的高兴值
如果Type=2,接下来两个整数a,b,表示交换这两个位置的人
如果type=3,接下来三个整数l,r,t,表示把l个人的升高增加t,l+1个人增加2t…第r个人增加(r-l+1)t, (0<=t<= 10000)
输出说明:
对于每个询问按照顺序输出每个操作1的答案。
样例输入:
6 8
109 827 100 530 10 826
3 1 6 1
2 2 6
1 2 4
1 2 3
2 2 6
1 2 6
1 2 5
样例输出:
431
0
817
431
719
数据范围:
有20%的数据:n,m<=5000
另有10%的数据:没有第三种操作.
另有20%的数据: 没有第二种操作
对于100的数据:n,m<=100000
---------------------------------------------
样例有错
--------------------------------------------
方法一:
我们可以直接暴力。预计得分20分
方法二:
我们不考虑第三种操作,只需要维护一个最大值就可以了,预计得分40分
方法三:
我们考虑对于一段进行分段操作,分成sqrt(n)块。
有一个技巧是,我们求的是一段区间的最大值。我们把每个值a[i]修改为a[i]-a[i-1],这样的话问题变成求最大前缀和。而第三种操作就变成了对一段区间进行加t的操作。
对于每一个快,我们记录这一块的最大值maxs,和对一整段进行操作的话,后面能够超过这个最大值的最小的是多少min。
那么对于第二种操作我们直接暴力维护,时间复杂度o(sqrt(n));
对于第三种操作,如果跨立一个块得话,我们直接对这一段区间标记加上t。如果这个标记大于这一段的min的话,我们对这一块暴力进行维护。时间复杂度o(sqrt(n)).
对于第一种操作,我们可以变成求最大前缀和啦。时间复杂度o(sqrt(n));
这一整个时间复杂度为o((n+m)*sqrt(n));
复杂度十分玄学(我是看了贴吧的讨论写的)
----------------------------------------------------
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <cassert>
using namespace std;
typedef long long LL;
void read(LL &x) {
char c;bool flag = 0;
while((c=getchar())<'0'||c>'9') flag |= (c=='-');
x=c-'0';while((c=getchar())>='0'&&c<='9') x = x*10+c-'0';
flag?x=-x:x;
}
void read(int &x) {
char c;bool flag = 0;
while((c=getchar())<'0'||c>'9') flag |= (c=='-');
x=c-'0';while((c=getchar())>='0'&&c<='9') x = x*10+c-'0';
flag?x=-x:x;
}
const LL inf = ~0u>>2;
void FRE();
void upval(LL &a,const LL &b) {if(a<b) a=b;}
#define MAXX 101000
#define N 600
int n,m;
LL h[MAXX],bsf[N];
int bsiz,bl[N],br[N],bk[MAXX];
LL lazy1[N],lazy2[N];
struct pii{LL h,pos;pii(LL h=0,LL pos=0):h(h),pos(pos){}} st[N][N];
int top[N];
void reset(int bk) {
bsf[bk] = inf; top[bk] = 0;
for (LL i = bl[bk]; i <= br[bk]; i++) {
while(top[bk] && st[bk][top[bk]].h <= h[i]) top[bk]--;
st[bk][++top[bk]] = pii(h[i],i);
}
for (LL i = 2; i <= top[bk]; i++)
bsf[bk] = min(bsf[bk],
((st[bk][1].h-st[bk][i].h)/(st[bk][i].pos-st[bk][1].pos)));
}
void push_down(int bk) {
if(!lazy1[bk] && !lazy2[bk]) return;
for (LL i = bl[bk]; i <= br[bk]; i++)
h[i] += lazy1[bk]+i*lazy2[bk];
lazy1[bk] = lazy2[bk] = 0;
}
void Swap(int x,int y) {
push_down(bk[x]); push_down(bk[y]);
swap(h[x],h[y]);
reset(bk[x]); reset(bk[y]);
}
LL Max(int x,int y) {
int li = min(br[bk[x]],y); LL mx = 0;
push_down(bk[x]);
for (int i = x; i <= li; i++) upval(mx,h[i]);
reset(bk[x]);
for (int i = bk[x]+1; i < bk[y]; i++) {
if(lazy2[i] >= bsf[i] && lazy2[i]) {
push_down(i);
reset(i);
}
upval(mx,st[i][1].h+lazy1[i]+lazy2[i]*st[i][1].pos);
}
if(bk[x] != bk[y]) {
push_down(bk[y]);
for (int i = bl[bk[y]]; i <= y; i++) upval(mx,h[i]);
reset(bk[y]);
}
mx -= h[1]+lazy1[bk[1]]+lazy2[bk[1]];
return mx>0 ? mx:0;
}
void Add(int x,int y,LL t) {
int li = min(br[bk[x]],y); LL L = x-1;
push_down(bk[x]);
for (int i = x; i <= li; i++) h[i] += (i-L)*t;
reset(bk[x]);
for (int i = bk[x]+1; i < bk[y]; i++)
lazy1[i] += -L*t,lazy2[i] += t;
if(bk[x] != bk[y]) {
push_down(bk[y]);
for (int i = bl[bk[y]]; i <= y; i++) h[i] += (i-L)*t;
reset(bk[y]);
}
}
int main() {
FRE();
read(n); read(m);
bsiz = sqrt(n+0.5);
for (int i = 1; i <= n; i++) {
read(h[i]);
bk[i] = i/bsiz+1;
if(!bl[bk[i]]) bl[bk[i]] = i;
br[bk[i]] = i;
}
for (int i = 1; i <= bk[n]; i++) reset(i);
for (int i = 1,tp,x,y,t; i <= m; i++) {
read(tp); read(x); read(y);
if(tp == 1) printf("%lld\n",Max(x,y));
else if(tp == 2) Swap(x,y);
else read(t),Add(x,y,t);
}
return 0;
}
void FRE() {
assert(freopen("sdoi12_line.in","r",stdin));
assert(freopen("sdoi12_line.out","w",stdout));
}