• 【BZOJ4864】[BeiJing 2017 Wc]神秘物质 Splay


    【BZOJ4864】[BeiJing 2017 Wc]神秘物质

    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

    题解:易知任意区间中的极差的最大值就是整个区间的极差,任意极差的最小值一定是相邻两数之差的最小值,我们可以用Splay来维护以下几个信息

    1.区间最大值2.区间最小值3.区间相邻两数之差的最小值

    因为在Splay旋转过程中,相邻两数之差是不会变的,所以将相邻两数之差统一由在左边的那个数保存,查询时右端点-1就行了

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int tot,n,m,root;
    struct node
    {
    	int fa,ch[2],siz,sw,w,sm,sn,v;
    }s[200010];
    int num[200010];
    char str[20];
    int rd()
    {
    	int ret=0;	char gc=getchar();
    	while(gc<'0'||gc>'9')	gc=getchar();
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret;
    }
    void pushup(int x)
    {
    	s[x].siz=s[s[x].ch[0]].siz+s[s[x].ch[1]].siz+1;
    	s[x].sm=max(max(s[x].v,s[s[x].ch[0]].sm),s[s[x].ch[1]].sm);
    	s[x].sn=min(min(s[x].v,s[s[x].ch[0]].sn),s[s[x].ch[1]].sn);
    	s[x].sw=min(min(s[x].w,s[s[x].ch[0]].sw),s[s[x].ch[1]].sw);
    }
    void rotate(int x,int &k)
    {
    	int y=s[x].fa,z=s[y].fa,d=(x==s[y].ch[1]);
    	if(y==k)	k=x;
    	else	s[z].ch[y==s[z].ch[1]]=x;
    	s[x].fa=z,s[y].fa=x,s[y].ch[d]=s[x].ch[d^1];
    	if(s[x].ch[d^1])	s[s[x].ch[d^1]].fa=y;
    	s[x].ch[d^1]=y;
    	pushup(y),pushup(x);	
    }
    void splay(int x,int &k)
    {
    	while(x!=k)
    	{
    		int y=s[x].fa,z=s[y].fa;
    		if(y!=k)
    		{
    			if((x==s[y].ch[0])^(y==s[z].ch[0]))	rotate(x,k);
    			else	rotate(y,k);
    		}
    		rotate(x,k);
    	}
    }
    int find(int x,int y)
    {
    	if(!x)	return 0;
    	if(y<=s[s[x].ch[0]].siz)	return find(s[x].ch[0],y);
    	if(y==s[s[x].ch[0]].siz+1)	return x;
    	return find(s[x].ch[1],y-s[s[x].ch[0]].siz-1);
    }
    void build(int l,int r,int last)
    {
    	if(l>r)	return ;
    	int mid=l+r>>1;
    	s[mid].fa=last,s[last].ch[mid>last]=mid;
    	build(l,mid-1,mid),build(mid+1,r,mid);
    	pushup(mid);
    }
    int main()
    {
    	n=rd(),m=rd();
    	int i,a,b;
    	s[0].sn=s[0].sw=1<<30;
    	for(i=2;i<=n+1;i++)	s[i].v=rd();
    	for(i=2;i<=n+1;i++)	s[i].w=abs(s[i].v-s[i+1].v);
    	tot=n+2,root=tot+1>>1;
    	build(1,root-1,root),build(root+1,tot,root);
    	pushup(root);
    	for(i=1;i<=m;i++)
    	{
    		scanf("%s",str),a=rd(),b=rd();
    		switch(str[1])
    		{
    			case 'e':splay(find(root,a+1),root),splay(find(root,a+3),s[root].ch[1]);
    				s[s[root].ch[1]].ch[0]=0,pushup(s[root].ch[1]);
    				s[root].v=b,s[root].w=abs(b-s[s[root].ch[1]].v);
    				splay(find(root,a),s[root].ch[0]),s[s[root].ch[0]].w=abs(s[s[root].ch[0]].v-b);
    				pushup(s[root].ch[0]),pushup(root);	break;
    			case 'n':splay(find(root,a+1),root),splay(find(root,a+2),s[root].ch[1]);
    				s[s[root].ch[1]].ch[0]=++tot,s[tot].fa=s[root].ch[1],s[root].w=abs(s[root].v-b);
    				s[tot].v=b,s[tot].w=abs(b-s[s[root].ch[1]].v),pushup(tot);
    				pushup(s[root].ch[1]),pushup(root);	break;
    			case 'a':splay(find(root,a),root),splay(find(root,b+2),s[root].ch[1]);
    				printf("%d
    ",s[s[s[root].ch[1]].ch[0]].sm-s[s[s[root].ch[1]].ch[0]].sn);	break;
    			case 'i':splay(find(root,a),root),splay(find(root,b+1),s[root].ch[1]);
    				printf("%d
    ",s[s[s[root].ch[1]].ch[0]].sw);	break;
    		}
    	}
    	return 0;
    }
  • 相关阅读:
    nginx 配置文件详解
    nginx的location匹配规则
    mysql常用函数
    jquery封装的ajax请求
    docker
    in与exists和not in 与 not exists的区别
    mysql授权
    线程池
    springboot+rediscluster
    常用网址
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6801523.html
Copyright © 2020-2023  润新知