bzoj4864 [BeiJing 2017 Wc]神秘物质

(http://www.elijahqi.win/2018/01/26/bzoj4864-beijing-2017-wc%E7%A5%9E%E7%A7%98%E7%89%A9%E8%B4%A8/%20%E2%80%8E)
Description
21ZZ 年,冬。
小诚退休以后, 不知为何重新燃起了对物理学的兴趣。 他从研究所借了些实验仪器,整天研究各种微观粒子。这
一天, 小诚刚从研究所得到了一块奇异的陨石样本, 便迫不及待地开始观测。 在精密仪器的视野下,构成陨石
的每个原子都无比清晰。 小诚发现, 这些原子排成若干列, 每一列的结构具有高度相似性。于是,他决定对单
独一列原子进行测量和测试。被选中的这列共有 N 个顺序排列的原子。 最初, 第 i 个原子具有能量 Ei。 随着
时间推移和人为测试, 这列原子在观测上会产生两种变化:
merge x e 当前第 x 个原子和第 x+1 个原子合并,得到能量为 e 的新原子;
insert x e 在当前第 x 个原子和第 x+1 个原子之间插入一个能量为 e 的新原子。
对于一列原子,小诚关心的是相邻一段中能量最大和能量最小的两个原子的能量差值,
称为区间极差。 因此, 除了观测变化外,小诚还要经常统计这列原子的两类数据:
max x y 当前第 x 到第 y 个原子之间的任意子区间中区间极差的最大值;
min x y 当前第 x 到第 y 个原子之间的任意子区间中区间极差的最小值。
其中, 子区间指的是长度至少是 2 的子区间。
小诚坚信这项研究可以获得诺贝尔物理学奖。为了让小诚早日了结心愿,你能否帮助他实现上述的观测和测量呢?
Input
第一行, 两个整数 N, M, 分别表示最初的原子数目和事件总数。
第二行, N 个整数 E1, E2, …, EN, 由空格隔开。依次表示每个原子的能量。
接下来 M 行, 每行为一个字符串和两个整数, 描述一次事件,格式见题目描述。
N<=100,000,M<=100,000
1 ≤ e, Ei ≤ 109。 设 N’ 为当前时刻原子数目。
对于 merge 类事件, 1 ≤ x ≤ N’-1;
对于 insert 类事件, 1 ≤ x ≤ N’;
对于 max 和 min 类事件, 1 ≤ x < y ≤ N’。
任何时刻,保证 N’ ≥ 2。
Output
输出若干行, 按顺序依次表示每次 max 和 min 类事件的测量结果。
Sample Input
4 3
5 8 10 2
max 1 3
min 1 3
max 2 4
Sample Output
5 2 8
我还是太菜了啊 想着想着就睡着了 还好订了闹钟三点 然后三点开始想 起来开始想写这题 没多久再次阵亡qwq其实后来早晨非常清醒之后 可以想明白 其实这个极值的最大 铁定是我整个区间的最大值减最小值 则极值最小呢一定是我相邻两个数 因为这样的话如果不相邻 那么有可能出现干扰 导致极值变大 所以我维护了序列的最左端的值 最右端的值 还有每个区间的极值最小 注意一些初值的给予 wa了好几发 合并的时候极值最小要更新 还有端点的值都要初始化 初始化的时候还有我维护的区间最小值和最大值也都需要初始化

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 0x3f3f3f3f
#define N 220000
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int size[N],v[N],a[N],c[N][2],fa[N],min1[N],max1[N],min2[N],left[N],right[N],n,m,cnt,root;
inline void update(int x){
    int l=c[x][0],r=c[x][1];left[x]=right[x]=inf;
    size[x]=size[l]+size[r]+1;left[x]=v[x];right[x]=v[x];min2[x]=min(min2[l],min2[r]);
    max1[x]=max(max1[l],max(v[x],max1[r]));min1[x]=min(min1[l],min(v[x],min1[r]));
    if (l) left[x]=left[l],min2[x]=min(min2[x],abs(v[x]-right[l]));
    if (r) right[x]=right[r],min2[x]=min(min2[x],abs(v[x]-left[r]));
}
inline void build(int f,int l,int r){
    if (l>r) return;int mid=l+r>>1;
    v[mid]=a[mid];c[f][mid>f]=mid;fa[mid]=f;if(v[mid]!=inf) min1[mid]=max1[mid]=v[mid];
    build(mid,l,mid-1);build(mid,mid+1,r);update(mid);
}
char op[10];
inline int find(int x,int sz){
    int l=c[x][0],r=c[x][1];
    if (size[l]+1==sz) return x;
    if (sz<=size[l]) return find(l,sz);else return find(r,sz-size[l]-1);
}
inline void rotate(int x,int &tar){
    int y=fa[x],z=fa[y];
    if (y==tar) tar=x;else c[z][c[z][1]==y]=x;
    int l=c[y][1]==x,r=l^1;
    fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
    c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void splay(int x,int &tar){
    while(x!=tar){
        int y=fa[x],z=fa[y];
        if (y!=tar){
            if(c[y][0]==x^c[z][0]==y) rotate(x,tar);else rotate(y,tar);
        }rotate(x,tar);
    }
}
inline int split(int x,int y){
    int xx=find(root,x),yy=find(root,y);
    splay(yy,root);splay(xx,c[root][0]);return c[xx][1];
}
inline void print(int x){
    if (c[x][0]) print(c[x][0]);
    //printf("%d %d %d %d\n",v[x],max1[x],min1[x],size[x]);
    printf("%d ",v[x]);
    if (c[x][1]) print(c[x][1]);
}
int main(){
    freopen("bzoj4864.in","r",stdin);
    n=read();m=read();cnt=n+2;root=n+3>>1;a[1]=inf;
    for (int i=2;i<=n+1;++i) a[i]=read(); a[n+2]=inf;
    min1[0]=min1[1]=min1[n+2]=min2[0]=inf;max1[0]=max1[1]=max1[n+2]=-inf;build(0,1,n+2);
    for (int i=1;i<=m;++i){
        scanf("%s",op);//print(root);puts("asdf");
        if (op[1]=='e'){
            int x=read(),e=read();int tmp=split(x+1,x+3),y=fa[tmp];
            v[y]=min1[y]=max1[y]=left[y]=right[y]=e;
            c[y][1]=0;min2[y]=inf;update(y);update(root);
        }
        if (op[1]=='n'){
            int x=read(),e=read();int xx=find(root,x+1),yy=find(root,x+2);
            splay(yy,root);splay(xx,c[root][0]);++cnt;v[cnt]=max1[cnt]=min1[cnt]=left[cnt]=right[cnt]=e;
            size[cnt]=1;c[xx][1]=cnt;min2[cnt]=inf;update(xx);update(root);fa[cnt]=xx;
        }
        if (op[1]=='a'){
            int x=read(),y=read();int tmp=split(x,y+2);
            printf("%d\n",max1[tmp]-min1[tmp]);
        }
        if (op[1]=='i'){
            int x=read(),y=read();int tmp=split(x,y+2);printf("%d\n",min2[tmp]); 
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值