zoukankan      html  css  js  c++  java
  • P1110 [ZJOI2007]报表统计

    传送门


    emm, 也不用什么权值线段树平衡树啊, set+单点修改不查询的线段树都接近最优解了......
    image
    好想而且很好写, 常数也不大。


    题意

    有n堆数,初始每堆只有一个数, 从左往右排成一列。
    三种操作:

    1.往某一堆的末尾插入一个数
    2.查询相邻两个数的差值(绝对值)的最小值
    3.查询任意两个数的最小差值(绝对值).

    题解

    emm, 由于根本没有删除操作, 那不是好像很好做的样子!
    第三种操作, 每次插入数字的时候, 用set维护一下前驱后继即可。

    考虑第二种操作, 大概是这么一个东西
    image
    每一列表示一堆, 蓝色和红色的边表示相邻的元素, 以及他们的差值
    我们只需要维护它的最小值就行了,

    可以发现蓝色的边是稳定的, 不会消失。 每次插入一个数的时候会和它上面的的那个数产生一条蓝边, 用一个变量维护最小值即可。

    然后红边就不一样了, 它是会消失的。 我插入一个数的时候, 这一堆数原来的红边就消失, 新的红边出现。

    但事实上,每一堆至多有一个红边, 用一个线段树维护它的最小值即可,
    每次插入是时修改一个当前红边的值, 即可
    线段树只需单点修改, 甚至不需要查询(直接用tree[1]即可, 即根节点的权值

    实现

    #include <iostream>
    #include <cstdio>
    #include <set>
    #include <vector> 
    #define l(x) (x*2)
    #define r(x) (x*2+1) 
    using  namespace std;
    
    inline int read(){
    	int num=0, flag=1; char c=getchar();
    	while(!isdigit(c) && c!='-') c=getchar();
    	if(c=='-') flag=-1;
    	while(isdigit(c)) num=num*10+c-'0', c=getchar();
    	return num*flag; 
    }
    
    inline int reads(){
    	int num=0; char c=getchar();
    	while((c<'A' || c>'Z') && c!='_') c=getchar();
    	while((c>='A' && c<='Z') || c=='_') num++, c=getchar();
    	return num;
    }
    
    inline int abs(int x){
    	return x<0?-x:x;
    }
    
    const int N = 600600;
    const int inf = 0x3f3f3f3f;
    int n, m, minv=inf, ming=inf;
    int a[N], las[N];
    set<int> s;
    
    struct segTree{
    	int tree[N<<2];
    	void push_up(int o){
    		tree[o] = min(tree[l(o)], tree[r(o)]);
    	}
    	
    	void build(int o, int l, int r){
    		tree[o] = inf;
    		if(l == r) return ;
    		
    		int mid = (l+r)/2;
    		build(l(o), l, mid);
    		build(r(o), mid+1, r);
    	}
    	
    	void update(int x, int v, int o=1, int l=1, int r=n){
    		if(l==r) {
    			tree[o] = v;
    			return ;
    		}
    		int mid = (l+r)/2;
    		if(x <= mid) update(x, v, l(o), l, mid);
    		else update(x, v, r(o), mid+1, r);
    		push_up(o);
    	} 	
    }t; 
    
    inline void insert(int v){
    	if(minv) {
    		if(s.count(v)) {
    			minv = 0;
    		}else{
    			int res = inf;
    			
    			auto x = s.lower_bound(v);
    			if(x!=s.begin()) x--, res = min(res, abs(*x-v));
    			x = s.upper_bound(v);
    			if(x!=s.end()) res = min(res, abs(*x-v));
    			
    			minv = min(minv, res);
    			
    			s.insert(v);
    		}
    	}
    }
    
    int main(){
    	n=read(), m=read();
    	t.build(1, 1, n);
    	
    	for(int i=1; i<=n; i++){
    		a[i] = las[i] = read(); 
    		insert(a[i]); 
    	}
    	for(int i=1; i<n; i++) t.update(i, abs(las[i] - a[i+1]));
    	
    	while(m--){
    		int type = reads();
    		if(type == 6){
    			int x=read(), v=read();
    			insert(v);
    			
    			ming = min(abs(las[x] - v), ming); 
    			las[x] = v;
    			
    			if(x != n) t.update(x, abs(las[x] - a[x+1]));
    		}else if(type == 7){
    			printf("%d
    ", min(ming, t.tree[1]));
    		}else{
    			printf("%d
    ", minv);
    		}
    	}
    	 
    	return 0;
    } 
    
  • 相关阅读:
    jQuery万能放大镜插件(普通矩形放大镜)
    Mysql增量写入Hdfs(二) --Storm+hdfs的流式处理
    Mysql增量写入Hdfs(一) --将Mysql数据写入Kafka Topic
    Spark SQL,如何将 DataFrame 转为 json 格式
    贝叶斯分类算法实例 --根据姓名推测男女
    从分治算法到 Hadoop MapReduce
    Actor模型浅析 一致性和隔离性
    写博客的思考
    scala模式匹配详细解析
    [转] Scala 中的异步事件处理
  • 原文地址:https://www.cnblogs.com/ltdjcoder/p/15423497.html
Copyright © 2011-2022 走看看