链接:https://ac.nowcoder.com/acm/contest/6164/C
来源:牛客网
题目描述
牛牛为了减(吃)肥(好),希望对他的零食序列有更深刻的了解,所以他把他的零食排成一列,然后对每一个零食的美味程度都打了分,现在他有可能执行两种操作:
eat k:吃掉当前的第k个零食。右边的零食全部往左移动一位(编号减一)。
query i j:查询当前第i个零食到第j个零食里面美味度最高的和最低的零食的美味度。
输入描述:
第一行包含两个数n, m,表示原始数组的元素个数和操作的个数。第二行包括n个数,表示原始数组。以下m行,每行格式为1 k或者2 i j,其中第一个数为1表示吃掉,为2表示询问。
输出描述:
对每个询问操作输出一行,包括两个数,表示该范围内的最小值和最大值。示例1
输入
10 4 1 5 2 6 7 4 9 3 1 5 2 2 8 1 3 1 6 2 2 8输出
2 9 1 7说明
1<=n, m<=10^6, 1<=m<=10^6,数组中的元素绝对值均不超过10^9
题解:线段树的区间最大值最小值以及点的删除。
建立结构体node,有五个变量,即 区间左右边界,区间的最大最小值,以及区间内的有效点个数。
删除的时候,是删除从左到右的第k个有效点,需要通过区间内的有效点个数来进行删除。
求解最大值最小值是指第i个有效点到第j个有效点的最大值与最小值,也需要区间内的有效点个数来求解。
具体详见代码。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <set> #include <stack> #include <queue> #include <vector> #include <string> #define cla(a, sum) memset(a, sum, sizeof(a)) #define rap(i, m, n) for(int i=m; i<=n; i++) #define rep(i, m, n) for(int i=m; i>=n; i--) #define bug printf("???\n") using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll, ll> P; const int Inf = 1e9+5; const double eps = 1e-8; const int maxn = 1e6+5; template <typename T> void read(T &x){ x = 0; int f = 1; char ch = getchar(); while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();} while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();} x *= f; } struct node{ int l,r; int num; int mx,mi; }f[4*maxn]; int n,m; int a[maxn]; int Mx,Mi; void push_up(int ans){ f[ans].mi =min(f[ans<<1].mi ,f[ans<<1|1].mi ); f[ans].mx =max(f[ans<<1].mx ,f[ans<<1|1].mx ); f[ans].num =f[ans<<1].num +f[ans<<1|1].num ; } void build(int ans,int l,int r){ f[ans].l =l;f[ans].r =r; if(l==r){ f[ans].mi=f[ans].mx =a[l]; f[ans].num =1;return ; } int mid=(l+r)>>1; build(ans<<1,l,mid); build(ans<<1|1,mid+1,r); push_up(ans); } void Delete(int ans,int num){ if(f[ans].l ==f[ans].r ){ f[ans].num =0; f[ans].mi =Inf;f[ans].mx =-Inf; return ; } int mid=(f[ans].l +f[ans].r )>>1; if(f[ans<<1].num>=num){ Delete(ans<<1,num); } else{ Delete(ans<<1|1,num-f[ans<<1].num ); } push_up(ans); } void query(int ans,int l,int r){//注意l和r代表有效点的个数 if(l==1&&r==f[ans].num ){//通过不断改变l和r使得寻找的区间刚好有r-l+1个有效点 Mi=min(Mi,f[ans].mi );//更新最大值和最小值 Mx=max(Mx,f[ans].mx ); return ; } int mid=(f[ans].l +f[ans].r )>>1; if(r<=f[ans<<1].num ){ query(ans<<1,l,r); } else if(l<=f[ans<<1].num){ query(ans<<1,l,f[ans<<1].num ); query(ans<<1|1,1,r-f[ans<<1].num ); } else { query(ans<<1|1,l-f[ans<<1].num ,r-f[ans<<1].num ); } } int main() { read(n);read(m); rap(i,1,n)read(a[i]); build(1,1,n); while(m--){ int ok,a,b; read(ok); if(ok==1){ read(a); Delete(1,a); } else { read(a);read(b); Mx=-Inf,Mi=Inf;//初始化最大最小值 query(1,a,b); printf("%d %d\n",Mi,Mx); } } return 0; }