SHU oj 422 风力观测 线段树
风力观测
发布时间: 2017年7月9日 18:17 最后更新: 2017年7月9日 21:04 时间限制: 1000ms 内存限制: 128M
小Y正在观测y地区的风力情况,他在一条直线上依此设定了n个观测点,并观测与直线垂直方向的风力值,风力有时是正向的也有时是反向的,规定正向时的风力值为正数,他发现每次风力值的变化都可以表示为观测点上一条线段[L,R]上的同时增强或者减弱。小Y希望能够实时统计这些观测点的数据,并且实时分析这些观测点在历史中到达的风力最大绝对值,但是他无法同时对大量的观测点进行分析, 更重要的是他记不住这些观测点过去的风力大小,于是他希望你来用计算机帮助他完成这个任务。
你简化了这个问题,将问题分为两种查询:
1.对观测点[L,R]上的风力正向增强X。(X为负数表示正向减弱,即反向加强)
2.查询观测点A上的历史风力最大绝对值。
第一行有一个整数T表示数据组数。(T<=10)
接着有T组数据,每组数据第一行是整数n和q,表示观测点个数和查询次数。
第二行有n个数a1,...,an,表示每个观测点的风力初始值。
接着有q行,表示q次操作,格式为:
1 L R X:表示对[L,R]线段上的正向风力同时增强x。
2 A:表示查询A点的历史风力最大绝对值。
1<=n,q<=100000。
1<=L,R,A<=n
−10000<=ai, X<=10000
对每次询问2,输出一个数字表示风力值并换行。
1 5 6 1 -1 2 3 -3 1 1 5 1 2 1 2 2 1 2 4 -5 2 2 2 3
2 1 5 3
题目链接:http://acmoj.shu.edu.cn/problem/422/
官方题解有注释
#include<iostream> #include<cstring> #include<cstdio> #include<map> #include<algorithm> using namespace std; #define mid (L+R)/2 #define ls 2*rt #define rs 2*rt|1 #define lson ls,L,mid #define rson rs,mid+1,R const int mx = 1e5+5; typedef pair<int,int> P; int MAX[mx<<3],MIN[mx<<3],lazy[mx<<3]; int a[mx]; int n,m; void push_down(int rt){ MAX[ls] = max(MAX[ls],MAX[rt]+lazy[ls]); MIN[ls] = min(MIN[ls],MIN[rt]+lazy[ls]); MIN[rs] = min(MIN[rs],MIN[rt]+lazy[rs]); MAX[rs] = max(MAX[rs],MAX[rt]+lazy[rs]); //因为上面的lazy已经更新过了所以再给下面用一遍会重复所以不只要增加还未更新的即可 lazy[rs] += lazy[rt]; lazy[ls] += lazy[rt]; lazy[rt] = MAX[rt] = MIN[rt] = 0; } void update(int rt,int L,int R,int l,int r,int v){ if(l<=L && R <= r){ lazy[rt]+=v; MAX[rt] = max(MAX[rt],lazy[rt]); //这一段如果没有被更新过就是直接这样 MIN[rt] = min(MIN[rt],lazy[rt]); //如果这一段被更新过的话再更新的时候只要取历史的最高还是一样的结果 return; } if(MAX[rt]||MIN[rt]||lazy[rt]) //如果其中有一个不为0那就更新 push_down(rt); if(l>mid) update(rson,l,r,v); else if(r<=mid) update(lson,l,r,v); else{ update(rson,mid+1,r,v); update(lson,l,mid,v); } } P query(int rt,int L,int R,int x){ if(L == R && L == x) return {MAX[rt],MIN[rt]}; if(MAX[rt]||MIN[rt]||lazy[rt]) push_down(rt); if(x > mid) return query(rson,x); else return query(lson,x); } int main(){ int t; scanf("%d",&t); while(t--){ memset(MAX,0,sizeof(MAX)); memset(MIN,0,sizeof(MIN)); memset(lazy,0,sizeof(lazy)); scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++) scanf("%d",&a[i]); while(m--){ int casei; scanf("%d",&casei); if(casei == 1){ int l,r,v; scanf("%d%d%d",&l,&r,&v); update(1,1,n,l,r,v); } else{ int x; scanf("%d",&x); P ans = query(1,1,n,x); printf("%d\n",max(abs(a[x]+ans.first),abs(a[x]+ans.second))); } } } return 0; }
另一种写法:
对于每颗线段树都是一时间为节点,而不是以原来的每个点为点,;
每个点对应一颗线段树,这颗线段树是以时间为点,进行更新;
巧妙的是,对于区间更新的方式,是从上一颗线段树继承下去的,有点可持久化的意思;
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<cstdio> #include<cmath> #include<string> #include<queue> #include<algorithm> #include<stack> #include<cstring> #include<vector> #include<list> #include<set> #include<map> using namespace std; #define LL long long #define pi (4*atan(1.0)) #define eps 1e-14 #define bug(x) cout<<"bug"<<x<<endl; const int N=1e5+10,M=2e6+10,inf=1e9+10; const LL INF=1e18+10,mod=1e9+7; struct SGT { int maxx[N<<2],minn[N<<2],lazy[N<<2]; void pushup(int pos) { maxx[pos]=max(maxx[pos<<1],maxx[pos<<1|1]); minn[pos]=min(minn[pos<<1],minn[pos<<1|1]); } void pushdown(int pos) { if(lazy[pos]) { maxx[pos<<1]+=lazy[pos]; maxx[pos<<1|1]+=lazy[pos]; lazy[pos<<1]+=lazy[pos]; lazy[pos<<1|1]+=lazy[pos]; minn[pos<<1]+=lazy[pos]; minn[pos<<1|1]+=lazy[pos]; lazy[pos]=0; } } void build(int l,int r,int pos) { lazy[pos]=minn[pos]=maxx[pos]=0; if(l==r)return; int mid=(l+r)>>1; build(l,mid,pos<<1); build(mid+1,r,pos<<1|1); } void update(int L,int R,int c,int l,int r,int pos) { if(L<=l&&r<=R) { maxx[pos]+=c; minn[pos]+=c; lazy[pos]+=c; return; } pushdown(pos); int mid=(l+r)>>1; if(L<=mid)update(L,R,c,l,mid,pos<<1); if(R>mid)update(L,R,c,mid+1,r,pos<<1|1); pushup(pos); } pair<int,int> query(int L,int R,int l,int r,int pos) { if(L<=l&&r<=R)return make_pair(minn[pos],maxx[pos]); pushdown(pos); int mid=(l+r)>>1; int maxx=-inf,minn=inf; if(L<=mid) { pair<int,int> le=query(L,R,l,mid,pos<<1); maxx=max(maxx,le.second); minn=min(minn,le.first); } if(R>mid) { pair<int,int> ri=query(L,R,mid+1,r,pos<<1|1); maxx=max(maxx,ri.second); minn=min(minn,ri.first); } return make_pair(minn,maxx); } }tree; int a[N],ans[N]; vector<pair<int,int> >v[N]; vector<int>qq[N]; int main() { int T; scanf("%d",&T); while(T--) { int n,q; scanf("%d%d",&n,&q); for(int i=1; i<=n; i++) scanf("%d",&a[i]),v[i].clear(),qq[i].clear(); for(int i=1;i<=q;i++) { ans[i]=inf*2; int t; scanf("%d",&t); if(t==1) { int l,r,val; scanf("%d%d%d",&l,&r,&val); v[l].push_back(make_pair(i,val)); if(r+1<=n)v[r+1].push_back(make_pair(i,-val)); } else { int val; scanf("%d",&val); qq[val].push_back(i); } } tree.build(1,q,1); for(int i=1;i<=n;i++) { for(int j=0;j<v[i].size();j++) tree.update(v[i][j].first,q,v[i][j].second,1,q,1); for(int j=0;j<qq[i].size();j++) { pair<int,int> out=tree.query(1,qq[i][j],1,q,1); //cout<<out.first<<" "<<out.second<<endl; ans[qq[i][j]]=max(abs(a[i]),max(abs(a[i]+out.first),abs(a[i]+out.second))); } } for(int i=1;i<=q;i++) if(ans[i]<inf*2) printf("%d\n",ans[i]); } return 0; }