zoukankan      html  css  js  c++  java
  • [noi2005][treap]序列维护

    这道题能用辣鸡度搜出来的treap做法只有两三篇吧,并且没有详解。。。

    先看数据范围,本蒟蒻感觉nlogn过不了啊。。。 [主要是我是大常数选手]

    其实可以勉强过,

    跪烂了那些只跑1s多的神犇%%%


    首先,四百万次的插入,如果你每次都申请一个新的空间,肯定是要MLE的。

    我们注意到数列中最多只有五十万个元素,也就是说我们最多同时用到五十万个空间。那么可以这样处理:维护一个栈,删除时将要删除的元素加到栈里,每次申请新的节点时先看栈里还有没有元素,如果有,那么将栈顶出栈,用于新申请的元素,否则新申请空间,,

    Treap *newnode (int xxx) {
    	if (top) return new (stk[top--]) Treap (xxx, Null);
    	return new (pool++) Treap (xxx, Null);
    }


    求区间最大值的话,对于一个节点多维护如下信息,以这个节点为根的子树代表的序列,最右边一段连续数值最大和是多少,最左边一段连续数值的最大和是多少,这段区间最大的一段连续子序列和是多少。(分别记为rmax, lmax, mmax)当前节点的值记为data, 当前节点所代表的子树的元素和为sum,size代表该子树元素个数。

    rmax可以这样转移 : 它等于 Max (右儿子的rmax,data + 右儿子的sum + Max (左儿子的rmax,0))。



    如图,DE代表当前节点的那个元素,BC为当前节点代表的子树,BD代表当前节点的左儿子所代表的子树,EC代表当前节点的右儿子所代表的子树,如果BC这段区间的rmax的那段区间在EC中,那么它就是CE的rmax,如果不在EC中,即左端点在E的左边,那么它就等于BE这段区间的rmax加上EC这段区间的和,BE这段区间的rmax怎么求呢?首先DE必须要选(因为左端点在e左边),那么我们就可以看BD的rmax了。如果BD的rmax < 0 ,那么选了他会让BC的rmax变小,不如不选。所以可以得出上面的式子。

    选右儿子同理。那么当前节点的mmax = Max (当前节点的lmax,当前节点的rmax,左儿子的mmax,右儿子的mmax,Max(0,左儿子的rmax)+Max(0,右儿子的lmax)+data)

    至于为什么这样,就留给你们自己思考啦。

    	void update () {
    		if (l != Null) l -> pushdown ();
    		if (r != Null) r -> pushdown ();
    		size = l -> size + r -> size + 1;
    		sum = l -> sum + r -> sum + data;
    		lmax = data + std :: max (r -> lmax, 0);
    		rmax = data + std :: max (l -> rmax, 0); 
    		if (l != Null) lmax = std :: max (l -> lmax, l -> sum + lmax);
    		if (r != Null) rmax = std :: max (r -> rmax, r -> sum + rmax);
    		mmax = std :: max (std :: max (l -> mmax, r -> mmax), std :: max (std :: max(lmax, rmax), std :: max (l -> rmax, 0) + std :: max (r -> lmax, 0) + data));
    	}

    那么怎样下放标记呢,对于翻转的标记,把左右儿子交换,将lmax , rmax交换即可。对于覆盖的标记,就是把data改成标记的值,sum改成data*size。如果data是大于零的,那么这段区间的最大值就应该是sum。(即lmax = rmax = mmax = sum) 否则,由于至少要选一个元素,那么最大值就为data (即lmax = rmax = mmax = data)。

    	void pushdown () {
    		if (l1) {
    			l -> l1 ^= 1; r -> l1 ^= 1; l1 ^= 1;
    			std :: swap (l, r);
    			std :: swap (lmax, rmax); 
    		}
    		if (l21) {
    			l -> l21 = r -> l21 = true;
    			l -> l22 = r -> l22 = l22;
    			l21 = false;
    			data = l22;
    			sum = data * size;
    			lmax = rmax = mmax = l22 > 0 ? sum : data;
    		}
    	}

    最后上代码,反正细节挺多的。。。 我语文不好,感觉对不住观众朋友QAQ

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<string>
    #include<iostream>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    
    const int N = 5e5 + 9;
    
    int top, n, m;
    
    struct Treap *Null;
    
    struct Treap {
    	int data, sum, size, hr, lmax, rmax, mmax; bool l1, l21; int l22;
    	Treap *l, *r;
    	Treap () {}
    	Treap (int data, Treap *fl) : data(data), sum(data), size(1), hr(rand()), lmax(data), rmax(data), mmax(data), l1(0), l21(0), l(fl), r(fl) {}
    	void update () {
    		if (l != Null) l -> pushdown ();
    		if (r != Null) r -> pushdown ();
    		size = l -> size + r -> size + 1;
    		sum = l -> sum + r -> sum + data;
    		lmax = data + std :: max (r -> lmax, 0);
    		rmax = data + std :: max (l -> rmax, 0); 
    		if (l != Null) lmax = std :: max (l -> lmax, l -> sum + lmax);
    		if (r != Null) rmax = std :: max (r -> rmax, r -> sum + rmax);
    		mmax = std :: max (std :: max (l -> mmax, r -> mmax), std :: max (std :: max(lmax, rmax), std :: max (l -> rmax, 0) + std :: max (r -> lmax, 0) + data));
    	}
    	void pushdown () {
    		if (l1) {
    			l -> l1 ^= 1; r -> l1 ^= 1; l1 ^= 1;
    			std :: swap (l, r);
    			std :: swap (lmax, rmax); 
    		}
    		if (l21) {
    			l -> l21 = r -> l21 = true;
    			l -> l22 = r -> l22 = l22;
    			l21 = false;
    			data = l22;
    			sum = data * size;
    			lmax = rmax = mmax = l22 > 0 ? sum : data;
    		}
    	}
    }*root, meme[N], *pool = meme, *stk[N];
    
    void rec (Treap *x) {
    	if (x == Null) return ;
    	rec (x -> l);
    	rec (x -> r);
    	stk[++top] = x;
    }
    
    Treap *newnode (int xxx) {
    	if (top) return new (stk[top--]) Treap (xxx, Null);
    	return new (pool++) Treap (xxx, Null);
    }
    
    Treap *Merge (Treap *A, Treap *B) {
    	if (A == Null) return B;
    	if (B == Null) return A;
    	if (A -> hr > B -> hr) {
    		B -> pushdown ();
    		B -> l = Merge (A, B -> l);
    		B -> update ();
    		return B;
    	} else {
    		A -> pushdown ();
    		A -> r = Merge (A -> r, B);
    		A -> update ();
    		return A;
    		
    	}
    }
    
    using std :: pair;
    typedef pair <Treap *, Treap *> Droot;
    
    Droot Split (Treap *x, int k) {
    	if (x == Null) return Droot (Null, Null);
    	Droot y; x -> pushdown ();
    	if (x -> l -> size >= k) {
    		y = Split (x -> l, k);
    		x -> l = y . second;
    		x -> update ();
    		y . second = x;
    	} else {
    		y = Split (x -> r, k - x -> l -> size - 1);
    		x -> r = y . first;
    		x -> update ();
    		y . first = x;
    	}
    	return y;
    }
    
    int num; bool fl; char a;
    
    int getin () {
    	num = fl = 0;
    	for (a = getchar (); a < '0' || a > '9'; a = getchar()) if (a == '-') fl = true;
    	for (; a >= '0' && a <= '9'; a = getchar()) num = (num << 3) + (num << 1) + a - '0';
    	if (fl) num = -num;
    	return num;
    }
    
    Treap *Build () {
    	Treap *x, *last; stk[1] = Null;
    	for (int i = 1; i <= n; ++i) {
    		x = new (pool++) Treap (getin (), Null); last = Null;
    		while (top && stk[top] -> hr > x -> hr) {
    			stk[top] -> update ();
    			last = stk[top--];
    		}
    		if (top) stk[top] -> r = x;
    		x -> l = last;
    		stk[++top] = x;
    	}
    	while (top) stk[top--] -> update ();
    	return stk[1];
    }
    
    Droot clc2, clc1;
    char opt[20]; Treap *clc3;
    
    int main () {
    	Null = new Treap (-0x7fffffff, NULL); Null -> size = Null -> sum = 0;
    	n = getin (); m = getin (); root = Build ();
    	while (m--) {
    		scanf ("%s", opt);
    		if (opt[2] == 'X') printf ("%d
    ", root -> mmax);
    		else if (opt[2] == 'S') {
    			clc1 = Split (root, getin());
    			clc3 = Null;
    			for (int i = getin(); i; --i) clc3 = Merge (clc3, newnode (getin()));
    			root = Merge (clc1 . first, Merge (clc3, clc1 . second));
    		} else {
    			clc1 = Split (root, getin() - 1);
    			clc2 = Split (clc1 . second, getin());
    			if (opt[2] == 'K') clc2 . first -> l21 = true, clc2 . first -> l22 = getin ();
    			if (opt[2] == 'V') clc2 . first -> l1 = true;
    			if (opt[2] == 'T') printf ("%d
    ", clc2 . first -> sum);
    			if (opt[2] == 'L') rec (clc2 . first), root = Merge (clc1 . first, clc2 . second);
    			else root = Merge (clc1 . first, Merge (clc2 . first, clc2 . second));
    		}
    	}
    	return 0;
    }


  • 相关阅读:
    SSH出现ls command not found
    SVN打包备份
    【转】Linux安装JDK1.7 prm
    任务
    java多线程
    JAVA开发中151个建议
    Linux Too Many OpenFiles
    【收藏】Linux tail命令
    Linux读取属性配置文件注意事项
    [转]Linux端口查看命令
  • 原文地址:https://www.cnblogs.com/dcoi-king/p/7491436.html
Copyright © 2011-2022 走看看