zoukankan      html  css  js  c++  java
  • SPOJ GSS系列(数据结构维护技巧入门)

    题目链接 GSS

    $GSS1$

    对于每个询问$l$, $r$,查询$a_{l}$, $a_{l+1}$, $a_{l+2}$, ..., $a_{r}$这个序列的最大字段和。

    建立线段树,每个节点维护四个信息

    $c$:当前区间的元素和

    $lc$:当前区间左端点开始的最大子序列和

    $rc$:当前区间右端点结束的最大子序列和

    $ret$:当前区间的答案

    于是我们建立线段树的时候预处理出每个节点的四个信息,查询的时候返回一个节点,这个节点的$ret$即为答案。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define lson		i << 1, L, mid
    #define rson		i << 1 | 1, mid + 1, R
    #define ls		i << 1
    #define rs		i << 1 | 1
    
    typedef long long LL;
    
    const int N = 1e5 + 10;
    
    struct node{
    	int c, lc, rc, ret;
    } t[N << 2];
    
    int n, q, l, r;
    
    void pushup(int i){
    	t[i].c = t[ls].c + t[rs].c;
    	t[i].lc = max(t[ls].lc, t[ls].c + t[rs].lc);
    	t[i].rc = max(t[rs].rc, t[rs].c + t[ls].rc);
    	t[i].ret = max(max(t[ls].ret, t[rs].ret), t[ls].rc + t[rs].lc);
    }
    
    void build(int i, int L, int R){
    	if (L == R){
    		scanf("%d", &t[i].ret);
    		t[i].c = t[i].lc = t[i].rc = t[i].ret;
    		return;
    	}
    
    	int mid = (L + R) >> 1;
    
    	build(lson);
    	build(rson);
    	pushup(i);
    }
    
    node query(int i, int L, int R, int l, int r){
    	if (l == L && R == r) return t[i];
    
    	int mid = (L + R) >> 1;
    
    	if (r <= mid) return query(lson, l, r);
    	if (l > mid)  return query(rson, l, r);
    
    	node ta = query(lson, l, mid);
    	node tb = query(rson, mid + 1, r);
    
    	node ans;
    	ans.c = ta.c + tb.c;
    	ans.lc = max(ta.lc, ta.c + tb.lc);
    	ans.rc = max(tb.rc, tb.c + ta.rc);
    	ans.ret = max(max(ta.ret, tb.ret), ta.rc + tb.lc);
    	return ans;
    }
    
    int main(){
    
    	while (~scanf("%d", &n)){
    		build(1, 1, n);
    		scanf("%d", &q);
    		while (q--){
    			scanf("%d%d", &l, &r);
    			node ans = query(1, 1, n, l, r);
    			printf("%d
    ", ans.ret);
    		}
    	}
    
    	return 0;
    }
    

     

    $GSS2$

    $GSS1$的去重版

    什么意思呢

    询问的形式还是完全一样的,就是子序列的价值稍微变了一下。

    $GSS1$中子序列的价值是该子序列的元素和,$GSS2$这里是该子序列出现过的元素的和

    做法和$GSS1$完全不一样。

    我们对询问离线。然后排序,按照右端点升序。

    然后从左往右扫过去,每次加入$a_{i}$的时候, 先把$a_{i}$加进去。

    接着我们对$last[a_{i}] + 1$到$i-1$这段区间都加上$a_{i}$,$last[x]$表示$x$上一次出现的位置,初值为$0$。

    维护线段树的话我们需要四个信息。

    $now$:当前这个时候区间的最大值

    $mx$:历史区间的最大值

    $h$:历史lazy标记(传给后代)的最大值

    $add$:当前lazy标记(需传给后代)的值

    然后查询一遍就可以了。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define lson		i << 1, L, mid
    #define rson		i << 1 | 1, mid + 1, R
    #define ls		i << 1
    #define rs		i << 1 | 1
    #define MP		make_pair
    #define fi		first
    #define se		second
    
    typedef long long LL;
    
    const int N = 1e5 + 10;
    const int d = 1e5;
    
    int n, m, x, y;
    int a[N], c[N << 1];
    vector <pair <int, int> > v[N];
    LL mx[N << 2], now[N << 2], add[N << 2], h[N << 2];
    LL ans[N];
    
    
    void pushup(int i){
    	mx[i] = max(mx[ls], mx[rs]);
    	now[i] = max(now[ls], now[rs]);
    }
    
    void pushdown(int i){
    	h[ls] = max(h[ls], add[ls] + h[i]);
    	h[rs] = max(h[rs], add[rs] + h[i]);
    
    	add[ls] += add[i];
    	add[rs] += add[i];
    
    	mx[ls] = max(mx[ls], now[ls] + h[i]);
    	mx[rs] = max(mx[rs], now[rs] + h[i]);
    
    	now[ls] += add[i];
    	now[rs] += add[i];
    
    	add[i] = 0;
    	h[i]   = -1e16;
    }
    
    
    void update(int i, int L, int R, int x, int val){
    	if (L == R && L == x){
    		mx[i] = now[i] = val;
    		return;
    	}
    
    	int mid = (L + R) >> 1;
    	pushdown(i);
    	if (x <= mid) update(lson, x, val);
    	else update(rson, x, val);
    	pushup(i);
    }
    
    void Add(int i, int L, int R, int l, int r, int val){
    	if (l <= L && R <= r){
    		now[i] += val;
    		mx[i] = max(mx[i], now[i]);
    		add[i] += val;
    		h[i] = max(h[i], add[i]);
    		return ;
    	}
    
    	int mid = (L + R) >> 1;
    	pushdown(i);
    	if (l <= mid) Add(lson, l, r, val);
    	if (r >  mid) Add(rson, l, r, val);
           	pushup(i);
    }
    
    LL query(int i, int L, int R, int l, int r){
    	if (l <= L && R <= r) return mx[i];
    	int mid = (L + R) >> 1;
    	LL ret = -1e16;
    	pushdown(i);
    	if (l <= mid) ret = max(ret, query(lson, l, r));
    	if (r > mid)  ret = max(ret, query(rson, l, r));
    	pushup(i);
    	return ret;
    }
    
    
    int main(){
    
    	scanf("%d", &n);
    	rep(i, 1, n) scanf("%d", a + i);
    	scanf("%d", &m);
    
    	rep(i, 1, ((n << 2) - 1)) mx[i] = h[i] = now[i] = -1e16;
    
    	rep(i, 1, m){
    		scanf("%d%d", &x, &y);
    		v[y].push_back(MP(x, i));
    	}
    
    	rep(i, 1, n){
    		update(1, 1, n, i, a[i]);
    		if (c[a[i] + d] + 1 < i) Add(1, 1, n, c[a[i] + d] + 1, i - 1, a[i]);
    		c[a[i] + d] = i;
    		for (auto u : v[i]) ans[u.se] = query(1, 1, n, u.fi, i);
    	}
    	
    	rep(i, 1, m) printf("%lld
    ", max(0ll, ans[i]));
    	return 0;
    }
    

     

    $GSS3$

    $GSS1$加个单点更新,没了。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define lson		i << 1, L, mid
    #define rson		i << 1 | 1, mid + 1, R
    #define ls		i << 1
    #define rs		i << 1 | 1
    
    typedef long long LL;
    
    const int N = 1e5 + 10;
    
    struct node{
    	int c, lc, rc, ret;
    } t[N << 2];
    
    int n, q, l, r;
    int op, x, y;
    
    void pushup(int i){
    	t[i].c = t[ls].c + t[rs].c;
    	t[i].lc = max(t[ls].lc, t[ls].c + t[rs].lc);
    	t[i].rc = max(t[rs].rc, t[rs].c + t[ls].rc);
    	t[i].ret = max(max(t[ls].ret, t[rs].ret), t[ls].rc + t[rs].lc);
    }
    
    void build(int i, int L, int R){
    	if (L == R){
    		scanf("%d", &t[i].ret);
    		t[i].c = t[i].lc = t[i].rc = t[i].ret;
    		return;
    	}
    
    	int mid = (L + R) >> 1;
    
    	build(lson);
    	build(rson);
    	pushup(i);
    }
    
    void update(int i, int L, int R, int x, int val){
    	if (L == x && L == R){
    		t[i].c = t[i].lc = t[i].rc = t[i].ret = val;
    		return;
    	}
    
    	int mid = (L + R) >> 1;
    	if (x <= mid) update(lson, x, val);
    	else update(rson, x, val);
    	pushup(i);
    }
    
    
    node query(int i, int L, int R, int l, int r){
    	if (l == L && R == r) return t[i];
    
    	int mid = (L + R) >> 1;
    
    	if (r <= mid) return query(lson, l, r);
    	if (l > mid)  return query(rson, l, r);
    
    	node ta = query(lson, l, mid);
    	node tb = query(rson, mid + 1, r);
    
    	node ans;
    	ans.c = ta.c + tb.c;
    	ans.lc = max(ta.lc, ta.c + tb.lc);
    	ans.rc = max(tb.rc, tb.c + ta.rc);
    	ans.ret = max(max(ta.ret, tb.ret), ta.rc + tb.lc);
    	return ans;
    }
    
    int main(){
    
    	scanf("%d", &n);
    	build(1, 1, n);
    	scanf("%d", &q);
    	while (q--){
    		scanf("%d", &op);
    		if (op == 1){
    			scanf("%d%d", &l, &r);
    			node ans = query(1, 1, n, l, r);
    			printf("%d
    ", ans.ret);
    		}
    
    		else{
    			scanf("%d%d", &x, &y);
    			update(1, 1, n, x, y);
    		}
    	}
    
    
    	return 0;
    }
    

     

    $GSS4$

    这题做法很暴力

    对那些值已经全部是1的区间结点打上永久标记即可。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define ls		i << 1
    #define rs		i << 1 | 1
    #define lson		ls, L, mid
    #define rson		rs, mid + 1, R
    
    typedef long long LL;
    
    const int N = 1e5 + 10;
    
    LL s[N << 2];
    int t[N << 2];
    int n;
    int q;
    int ca = 0;
    
    inline void pushup(int i){
    	s[i] = s[ls] + s[rs];
    	t[i] = t[ls] & t[rs];
    }
    
    void build(int i, int L, int R){
    	if (L == R){
    		scanf("%lld", s + i);
    		t[i] = s[i] <= 1;
    		return;
    	}
    
    	int mid = (L + R) >> 1;
    
    	build(lson);
    	build(rson);
    	pushup(i);
    }
    
    void update(int i, int L, int R, int l, int r){
    	if (t[i]) return;
    	if (L == R){
    		s[i] = sqrt(s[i]);
    		t[i] = s[i] <= 1;
    		return;
    	}
    
    	int mid = (L + R) >> 1;
    	if (l <= mid) update(lson, l, r);
    	if (r >  mid) update(rson, l, r);
    	pushup(i);
    }
    
    LL query(int i, int L, int R, int l, int r){
    	if (l <= L && R <= r) return s[i];
    	int mid = (L + R) >> 1;
    	LL ret = 0;
    	if (l <= mid) ret += query(lson, l, r);
           	if (r > mid)  ret += query(rson, l, r);
    	return ret;
    }	
    
    int main(){
    
    	while (~scanf("%d", &n)){
    		printf("Case #%d:
    ", ++ca);
    		build(1, 1, n);
    		scanf("%d", &q);
    		while (q--){
    			int op, x, y;
    			scanf("%d%d%d", &op, &x, &y);
    			if (x > y) swap(x, y);
    			if (op == 1) printf("%lld
    ", query(1, 1, n, x, y));
    			else update(1, 1, n, x, y);
    		}
    		putchar(10);
    	}
    	return 0;
    }
    

      

    $GSS5$

    分类讨论,注意细节就可以了。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define lson		i << 1, L, mid
    #define rson		i << 1 | 1, mid + 1, R
    #define ls		i << 1
    #define rs		i << 1 | 1
    
    const int N = 1e5 + 10;
    
    struct node{
    	int c, lc, rc, ret;
    } t[N << 2];
    
    int T;
    int n, q, l, r;
    int a[N], s[N];
    int ans;
    
    void pushup(int i){
    	t[i].c = t[ls].c + t[rs].c;
    	t[i].lc = max(t[ls].lc, t[ls].c + t[rs].lc);
    	t[i].rc = max(t[rs].rc, t[rs].c + t[ls].rc);
    	t[i].ret = max(max(t[ls].ret, t[rs].ret), t[ls].rc + t[rs].lc);
    }
    
    void build(int i, int L, int R){
    	if (L == R){
    		t[i].ret = a[L];
    		t[i].c = t[i].lc = t[i].rc = t[i].ret;
    		return;
    	}
    
    	int mid = (L + R) >> 1;
    
    	build(lson);
    	build(rson);
    	pushup(i);
    }
    
    node query(int i, int L, int R, int l, int r){
    	if (l == L && R == r) return t[i];
    
    	int mid = (L + R) >> 1;
    
    	if (r <= mid) return query(lson, l, r);
    	if (l > mid)  return query(rson, l, r);
    
    	node ta = query(lson, l, mid);
    	node tb = query(rson, mid + 1, r);
    
    	node ans;
    	ans.c = ta.c + tb.c;
    	ans.lc = max(ta.lc, ta.c + tb.lc);
    	ans.rc = max(tb.rc, tb.c + ta.rc);
    	ans.ret = max(max(ta.ret, tb.ret), ta.rc + tb.lc);
    	return ans;
    }
    
    int main(){
    
    	scanf("%d", &T);
    	while (T--){
    		scanf("%d", &n);
    		rep(i, 1, n) scanf("%d", a + i);
    		rep(i, 1, n) s[i] = s[i - 1] + a[i];
    		build(1, 1, n);
    		scanf("%d", &q);
    		while (q--){
    			int x1, y1, x2, y2;
    			scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
    			ans = 0;
    			if (x2 == y1){
    				ans = query(1, 1, n, x1, y1).rc + query(1, 1, n, x2, y2).lc - a[y1];
    				printf("%d
    ", ans);
    			}
    
    			else if (y1 < x2){
    				ans = s[x2 - 1] - s[y1];
    				ans += query(1, 1, n, x1, y1).rc + query(1, 1, n, x2, y2).lc;
    				printf("%d
    ", ans);
    			}
    
    			else{
    				ans = query(1, 1, n, x2, y1).ret;
    				ans = max(ans, s[y1 - 1] - s[x2] + query(1, 1, n, x1, x2).rc + query(1, 1, n, y1, y2).lc);
    				ans = max(ans, query(1, 1, n, x1, x2).rc + query(1, 1, n, x2, y1).lc - a[x2]);
    				ans = max(ans, query(1, 1, n, x2, y1).rc + query(1, 1, n, y1, y2).lc - a[y1]);
    				printf("%d
    ", ans);
    			}
    		}
    			
    	}
    
    
    	return 0;
    }
    

      

  • 相关阅读:
    具有快表的地址变换机构
    npm更换淘宝镜像
    内存扩充技术
    内存管理的概念
    内存的基础知识
    102. 二叉树的层序遍历
    104. 二叉树的最大深度
    206. 反转链表
    mysql 多字段查询,全局搜素
    java 处理html转义字符
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/7616214.html
Copyright © 2011-2022 走看看