线段树 [HZOI 2015]聪聪的世界
背景:
聪聪的性取向有问题。
题目描述:
聪聪遇到了一个难题:
给出一个序列a1…an,完成以下操作:
1 x 询问从x向左数第一个<ax的数;
2 x 询问从x向左数第一个>ax的数;
3 x 询问从x向右数第一个<ax的数;
4 x 询问从x向右数第一个>ax的数;
5 x y 交换ax与ay;
6 x y w 给ax…ay加上w;
7 x y w 给ax…ay减去w。
聪聪急切的想知道答案,因为他完成任务后就可以迎娶高富帅,出任CEO,走上人生巅峰,成为人生赢家!
请你帮帮他。
【输入格式】
第一行 n,m。
第二行 a1…an。
第三行到m+2行为以上七个操作。
【输出格式】
对于每个op>=1且op<=4输出一行表示答案,无解输出-1。
【样例输入】
5 5
8 2 0 0 9
1 2
5 1 3
7 1 3 1
4 2
1 1
【样例输出】
-1
7
-1
【提示】
10% n,m<=10000
40% n,m<=100000
100% n,m<=1000000
对于所有输入的数保证在[0,10^9]范围内
注:聪聪,出题人和高富帅都是往届大佬
要求一个点最靠近它且大于(小于)的值,有两种考虑方法,一是记录所查节点的位置,从根往下搜,
以找右边较大为例,在左子树下标大于所查点的前提下,尽量往左子树走,否则向右子树。
就这么干找。。。
第二种方法,(我打的就是这种非主流。。)从叶子节点往上找,
同样以右边较大为例,
如果在左子树,而右子树有大于它的,去右子树向下搜,否则爬向父亲。
如果在右子树,直接爬到父亲(因为无法向下走了)
而在向下走时,同样,尽量走左子树,否则走右子树。
向左走反之。
最重要的是本题涉及lazy操作,什么时候要传的计算好,我就不写了。
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<iostream> #define ll long long #define N 1000000 using namespace std; ll n,m,a[N+5],b[N+5]; struct node { ll l,r,h,k,lazy; } t[4*N+5]; ll read() { ll sum=0,f=1;char x=getchar(); while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();} while(x>='0'&&x<='9'){sum=sum*10+x-'0';x=getchar();} return sum*f; } inline void pushup(ll x) { t[x].h=max(t[x*2].h,t[x*2+1].h); t[x].k=min(t[x*2].k,t[x*2+1].k); } inline void pushdown(ll x) { ll l=t[x].lazy; t[x*2].h+=l;t[x*2].k+=l;t[x*2].lazy+=l; t[x*2+1].h+=l;t[x*2+1].k+=l;t[x*2+1].lazy+=l; t[x].lazy=0; } inline void build(ll l,ll r,ll x) { t[x].l=l;t[x].r=r;t[x].lazy=0; if(l==r) { t[x].k=t[x].h=a[l]; b[l]=x; return ; } ll mid=(l+r)/2; build(l,mid,x*2); build(mid+1,r,x*2+1); pushup(x); } inline void pllus(ll l,ll r,ll k,ll x) { if(t[x].l>=l&&t[x].r<=r) { t[x].h+=k;t[x].k+=k; t[x].lazy+=k; return; } if(t[x].lazy)pushdown(x); ll mid=(t[x].l+t[x].r)/2; if(l<=mid) pllus(l,r,k,x*2); if(r>mid) pllus(l,r,k,x*2+1); if(t[x].l!=t[x].r) pushup(x); } void wohh(ll x) { if(x!=1) wohh(x/2); if(t[x].lazy&&t[x].l!=t[x].r) pushdown(x); } inline void change(ll x,ll y) { ll f; wohh(b[x]); wohh(b[y]); f=t[b[x]].h; pllus(x,x,t[b[y]].h-t[b[x]].h,1); pllus(y,y,f-t[b[y]].h,1); } inline ll min_ldown(ll k,ll x) { if(t[x].l==t[x].r) return t[x].h; if(t[x].lazy&&t[x].l!=t[x].r)pushdown(x); if(t[x*2+1].k<k) return min_ldown(k,x*2+1); else return min_ldown(k,x*2); } inline ll min_lup(ll k,ll x) { if(x==1)return -1; if(x&1) { if(t[x^1].k<k) return min_ldown(k,x^1); else return min_lup(k,x/2); } else return min_lup(k,x/2); } inline ll min_rdown(ll k,ll x) { if(t[x].l==t[x].r) return t[x].h; if(t[x].lazy&&t[x].l!=t[x].r)pushdown(x); if(t[x*2].k<k) return min_rdown(k,x*2); else return min_rdown(k,x*2+1); } inline ll min_rup(ll k,ll x) { if(x==1)return -1; if(!(x&1)) { if(t[x^1].k<k) return min_rdown(k,x^1); else return min_rup(k,x/2); } else return min_rup(k,x/2); } inline ll max_rdown(ll k,ll x) { if(t[x].l==t[x].r) return t[x].h; if(t[x].lazy&&t[x].l!=t[x].r)pushdown(x); if(t[x*2].h>k) return max_rdown(k,x*2); else return max_rdown(k,x*2+1); } inline ll max_rup(ll k,ll x) { if(x==1)return -1; if(!(x&1)) { if(t[x^1].h>k) return max_rdown(k,x^1); else return max_rup(k,x/2); } else return max_rup(k,x/2); } inline ll max_ldown(ll k,ll x) { if(t[x].l==t[x].r) return t[x].h; if(t[x].lazy&&t[x].l!=t[x].r)pushdown(x); if(t[x*2+1].h>k) return max_ldown(k,x*2+1); else return max_ldown(k,x*2); } inline ll max_lup(ll k,ll x) { if(x==1)return -1; if((x&1)) { if(t[x^1].h>k) return max_ldown(k,x^1); else return max_lup(k,x/2); } else return max_lup(k,x/2); } int yjn() { freopen("ccsworld.in","r",stdin); freopen("ccsworld.out","w",stdout); n=read();m=read(); ll op,x,y,z; for(ll i=1;i<=n;i++)a[i]=read(); build(1,n,1); while(m--) { op=read();x=read(); switch(op) { case 1 :wohh(b[x]);printf("%lld\n",min_lup(t[b[x]].h,b[x]));break; case 2 :wohh(b[x]);printf("%lld\n",max_lup(t[b[x]].h,b[x]));break; case 3 :wohh(b[x]);printf("%lld\n",min_rup(t[b[x]].h,b[x]));break; case 4 :wohh(b[x]);printf("%lld\n",max_rup(t[b[x]].h,b[x]));break; case 5 :y=read();change(x,y);break; case 6 :y=read();z=read();pllus(x,y,z,1);break; case 7 :y=read();z=read();pllus(x,y,-z,1);break; } } } int qty=yjn(); int main(){;}