wows 线段树+差分
【问题描述】
山山最近在玩一款游戏叫战舰世界(steam 游戏太少了),他被大舰巨炮的魅力折服,于
是山山开了一局游戏,这次发现目标是一艘战列舰新墨西哥级,舰桥很高,原本应该打在目
标身后的圆形水域内的炮弹,都打在了舰桥上,于是落点变成了一条直线。
因为新墨西哥中间高两边低,所以按概率算,炮弹命中数中间多,两边少,并且中央区
域容易穿透出现高伤害,所以 山山向中间发射的炮弹比两边多,因为他有强迫症,所以一
个位置炮弹发射数相对于上一个位置的数目的变化量为 ki(整体大概构成一个山峰状),新墨
西哥操纵者因为 OI 的时候玩游戏,脑袋被教练按键盘了,所以站着不动,导致山山能够百
发百中,求数轮齐射后,在一段区域的命中数为阶梯增长的长度 (阶梯增长为 A+0K,
A+1K· · ·K 随意取,单调增)
(为了便于统计伤害,我们把新墨西哥分成 n 段,同时也
便于瞄准。
新墨西哥被教练抓着脑袋摁键盘了,我就不信我也 gbhghuyjhhfdhsfdhndxf......
【输入格式】
输入文件名为 wows.in。
第一行 n m, 表示新墨西哥被分成 n 段, 山山开炮数和询问命中次数的总数,
第二行以后每行开头一个 f,0 表示开炮,1 表示询问
如果开炮 后面还有 5 个参数 l,r,a,k,p
表示 山山向 l 到 r 段开炮,l 段开了 a 炮,以后 l + 1 到 p 段分别开 a+k,a+k+k,
a+k+k+k·
·
·炮, p+1 到 r 段开 a+(p-l-1)k、a+(p-l-2)k··
·炮
如果询问 后面有 l,r 表示询问区域(保证任意相邻区段数据之差在任何时候在 int 内)
【输出格式】
输出文件名为 wows.out。
对于每个询问输出一个数,表示符合要求的最大长度,后跟一个回车
【数据范围与约定】
这题是这次考试中最难的,我本来还欣喜地打了三十分的暴力,但是是世态炎凉,一个点都没捞到。。。
接下来是正解(来自我们谭巨佬的思想和方法):
首先我们要理解题意,他每次让我们修改两段区间,然后在线询问我们区间中最长等差长度。
恩。。。
可以知道很变态,现在我们来慢慢把题目变简单。
因为每次问的是相邻区间的差,所以我们将计就计,用一个差分数组c[i]保存a[i+1]-a[i]。
这样简化了之后,假如我们拿到第一组样例,就会这样(这是第一次):
num 2 3 4 5 6
c 2 2 -2 -2 -2
这样理解了后,我们就要考虑怎么优化这个差分数组,可以在时限内解决问题。
现在,每次询问其实就是问在范围内最长的相同的差分数组。
于是我们用线段树来维护这个值。
每个线段树节点维护:
ls,rs:区间最左右边连续相同的长度。
lp,rp:区间最左右边连续相同的数字。
s:区间最长连续相等区间(目标)。
合并区间时:
c[rt].ls=c[rt<<1].ls,c[rt].rs=c[(rt<<1)+1].rs;
c[rt].lp=c[rt<<1].lp,c[rt].rp=c[(rt<<1)+1].rp;
c[rt].s=max(c[rt<<1].s,c[(rt<<1)+1].s);
然后是一些细节:
当左边区间的差分数组都相等,并且右边区间最左边的数和左边区间最右边的数相等,那么我们就可以直接把右边区间最左边长度加到新区间上。
反之亦然。
然后是两个区间对s的影响:
如果左边区间最右边数字和右边区间最左边数字相等,那么就可以合并。
所以有:
c[rt].s=max(c[rt].s,c[rt<<1].rs+c[(rt<<1)+1].ls);
另外,这种线段树和平时写的线段树不一样,
在修改和查询的时候,必须要当前区间全部包括才能修改和查询,所以会有不一样。
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define ll long long #define il inline #define db double #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) using namespace std; il int gi() { int x=0,y=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') y=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*y; } struct node { int ls,rs; int lp,rp; int s; int l,r; }c[4000045]; int lazy[4000045]; il node merge(node L,node R)//he bing liang ge jie dian,fan hui yi ge jie dian { node tmp; int mid=L.r; tmp.l=L.l; tmp.r=R.r; tmp.ls=L.ls; tmp.rs=R.rs; tmp.lp=L.lp; tmp.rp=R.rp; if(L.rs==L.r-L.l+1&&L.rp==R.lp) tmp.ls+=R.ls;//xi jie 1 if(R.ls==R.r-R.l+1&&R.lp==L.rp) tmp.rs+=L.rs; tmp.s=max(L.s,R.s); if(L.rp==R.lp) tmp.s=max(tmp.s,L.rs+R.ls); return tmp; } void build(int rt,int l,int r) { if(l>r) return; if(l==r) { c[rt].l=c[rt].r=l; c[rt].ls=c[rt].rs=1; c[rt].lp=c[rt].rp=0; c[rt].s=1; return; } int mid=(l+r)>>1; build(rt<<1,l,mid); build((rt<<1)+1,mid+1,r); c[rt]=merge(c[rt<<1],c[(rt<<1)+1]); } void pushdown(int rt) { if(lazy[rt]) { lazy[rt<<1]+=lazy[rt]; lazy[(rt<<1)+1]+=lazy[rt]; c[rt<<1].lp+=lazy[rt]; c[rt<<1].rp+=lazy[rt]; c[(rt<<1)+1].lp+=lazy[rt]; c[(rt<<1)+1].rp+=lazy[rt]; lazy[rt]=0; } else return; } void add(int rt,int l,int r,int L,int R,int num) { if(l>r) return; if(l==L&&r==R) { c[rt].lp+=num; c[rt].rp+=num; lazy[rt]+=num; return; } int mid=(l+r)>>1; pushdown(rt); //xi mian de xiu gai bi xu quan bu bao han,suo yi bu yi yang if(L>mid) add((rt<<1)+1,mid+1,r,L,R,num); else if(R<=mid) add(rt<<1,l,mid,L,R,num); else { add(rt<<1,l,mid,L,mid,num); add((rt<<1)+1,mid+1,r,mid+1,R,num); } c[rt]=merge(c[rt<<1],c[(rt<<1)+1]); } node query(int rt,int l,int r,int L,int R) { if(L==l&&R==r) return c[rt]; int mid=(l+r)>>1; pushdown(rt); c[rt]=merge(c[rt<<1],c[(rt<<1)+1]); //he xiu gai yi yang if(L>mid) return query((rt<<1)+1,mid+1,r,L,R); else if(R<=mid) return query(rt<<1,l,mid,L,R); else { node r1=query(rt<<1,l,mid,L,mid); node r2=query((rt<<1)+1,mid+1,r,mid+1,R); return merge(r1,r2); } } int main() { freopen("wows.in","r",stdin); freopen("wows.out","w",stdout); int n=gi(),m=gi(); build(1,1,n-1); int l,r,a,k,p,H; for(int i=1;i<=m;i++) { H=gi(); if(H==0) { l=gi(),r=gi(),a=gi(),k=gi(),p=gi(); if(l!=1) add(1,1,n-1,l-1,l-1,a); if(l<=p-1) add(1,1,n-1,l,p-1,k); if(p<=r-1) add(1,1,n-1,p,r-1,-k); if(r!=n) add(1,1,n-1,r,r,-a-(2*p-l-r)*k); } else { l=gi(),r=gi(); if(l==r) printf("1\n"); else printf("%d\n",query(1,1,n-1,l,r-1).s+1); } } return 0; }