SPOJ1557 GSS2 Can you answer these queries II 线段树
Posted itst
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SPOJ1557 GSS2 Can you answer these queries II 线段树相关的知识,希望对你有一定的参考价值。
题意:给出一个长度为$N$的数列,$Q$次询问,每一次询问$[l,r]$之间的最大子段和,相同的数只计算一次。所有数字的绝对值$leq 10^5$
GSS系列中不板子的大火题,单独拿出来写
因为相同的数字只计算一次,像GSS1中的合并操作就无法进行,传统做法失效,我们需要一种更强大的做法。
考虑到去重,与HH的项链很相似,所以考虑离线、对询问以$r$从小到大进行排序后进行计算。
考虑到每一次$r$的增加都会产生新的可能的最大子段和,我们用如下方式维护线段树:对于第$i$个叶子节点,它包含两个元素:$sum$表示$sum limits_i^r num_i$(不算重复元素),$hisMax$表示$sum limits_i^r num_i$在曾经的过程中取到的最大值(也就是左端点为$l$,右端点在$[l,r]$之间的最大子段和)。而对于每一个非叶子节点,它的$sum$和$hisMax$都取其左右儿子的最大值。这样每一次询问操作只需要询问$[l,r]$的$hisMax$即可。
对于$r$的右移操作,设$pre_i$表示数字$i$最后一次出现的位置,将右端点从$r$移到$r+1$的过程就是对$pre_{num_{r+1}}$到$r+1$的所有位置加上$num_{r+1}$的操作。
考虑到复杂度,所以我们需要用到懒标记,而pushdown在其中是十分讲究的,具体代码和解释在下面
($h\_tag$表示$hisMax$的标记(相当于在当前$hisMax$还需要加多少),$s\_tag$表示$sum$的懒标记)
inline void pushdown(int now){ if(Tree[now].h_tag){ Tree[lch].hisMax = max(Tree[lch].hisMax , Tree[lch].sum + Tree[now].h_tag); Tree[rch].hisMax = max(Tree[rch].hisMax , Tree[rch].sum + Tree[now].h_tag); Tree[lch].h_tag = max(Tree[lch].h_tag , Tree[lch].s_tag + Tree[now].h_tag); Tree[rch].h_tag = max(Tree[rch].h_tag , Tree[rch].s_tag + Tree[now].h_tag); /* h_tag和hisMax实质上都是前缀最大值 在一个后缀加入的时候(也就是Tree[now].h_tag传下来的时候),s_tag和sum可以跟当前的h_tag接上变成一个新的前缀
而s_tag与h_tag两个标记对应的区间的左端点一定是一致的,sum和hisMax显然是一致的,于是h_tag和hisMax可以这样转移 */ Tree[now].h_tag = 0; } if(Tree[now].s_tag){ Tree[lch].sum += Tree[now].s_tag; Tree[rch].sum += Tree[now].s_tag; Tree[lch].s_tag += Tree[now].s_tag; Tree[rch].s_tag += Tree[now].s_tag; Tree[now].s_tag = 0; }//这个没什么好说的,基本的线段树操作 } //注意一定要先传h_tag再传s_tag,因为h_tag和hisMax传下来的时候是与之前的那一段进行连接,而不是与当前计算的这一段进行连接
完整代码:
1 #include<bits/stdc++.h> 2 #define lch (now << 1) 3 #define rch (now << 1 | 1) 4 #define mid ((l + r) >> 1) 5 #define int long long 6 //This code is written by Itst 7 using namespace std; 8 9 inline int read(){ 10 int a = 0; 11 bool f = 0; 12 char c = getchar(); 13 while(c != EOF && !isdigit(c)){ 14 if(c == ‘-‘) 15 f = 1; 16 c = getchar(); 17 } 18 while(c != EOF && isdigit(c)){ 19 a = (a << 3) + (a << 1) + (c ^ ‘0‘); 20 c = getchar(); 21 } 22 return f ? -a : a; 23 } 24 25 const int MAXN = 100010; 26 struct node{ 27 int sum , hisMax , s_tag , h_tag; 28 }Tree[MAXN << 2]; 29 struct query{ 30 int l , r , ind; 31 }now[MAXN]; 32 map < int , int > appear; 33 int N , Q , num[MAXN] , ans[MAXN]; 34 35 bool operator <(query a , query b){ 36 return a.r < b.r; 37 } 38 39 inline void pushup(int now){ 40 Tree[now].sum = max(Tree[lch].sum , Tree[rch].sum); 41 Tree[now].hisMax = max(Tree[lch].hisMax , Tree[rch].hisMax); 42 } 43 44 inline void pushdown(int now){ 45 if(Tree[now].h_tag){ 46 Tree[lch].hisMax = max(Tree[lch].hisMax , Tree[lch].sum + Tree[now].h_tag); 47 Tree[rch].hisMax = max(Tree[rch].hisMax , Tree[rch].sum + Tree[now].h_tag); 48 Tree[lch].h_tag = max(Tree[lch].h_tag , Tree[lch].s_tag + Tree[now].h_tag); 49 Tree[rch].h_tag = max(Tree[rch].h_tag , Tree[rch].s_tag + Tree[now].h_tag); 50 Tree[now].h_tag = 0; 51 } 52 if(Tree[now].s_tag){ 53 Tree[lch].sum += Tree[now].s_tag; 54 Tree[rch].sum += Tree[now].s_tag; 55 Tree[lch].s_tag += Tree[now].s_tag; 56 Tree[rch].s_tag += Tree[now].s_tag; 57 Tree[now].s_tag = 0; 58 } 59 } 60 61 void modify(int now , int l , int r , int L , int R , int add){ 62 if(l >= L && r <= R){ 63 Tree[now].s_tag += add; 64 Tree[now].sum += add; 65 Tree[now].hisMax = max(Tree[now].hisMax , Tree[now].sum); 66 Tree[now].h_tag = max(Tree[now].h_tag , Tree[now].s_tag); 67 return; 68 } 69 pushdown(now); 70 if(mid >= L) 71 modify(lch , l , mid , L , R , add); 72 if(mid < R) 73 modify(rch , mid + 1 , r , L , R , add); 74 pushup(now); 75 } 76 77 int query(int now , int l , int r , int L , int R){ 78 if(l >= L && r <= R) 79 return Tree[now].hisMax; 80 pushdown(now); 81 int maxN = 0; 82 if(mid >= L) 83 maxN = query(lch , l , mid , L , R); 84 if(mid < R) 85 maxN = max(maxN , query(rch , mid + 1 , r , L , R)); 86 return maxN; 87 } 88 89 signed main(){ 90 #ifndef ONLINE_JUDGE 91 freopen("1557.in" , "r" , stdin); 92 //freopen("1557.out" , "w" , stdout); 93 #endif 94 N = read(); 95 for(int i = 1 ; i <= N ; ++i) 96 num[i] = read(); 97 Q = read(); 98 for(int i = 1 ; i <= Q ; ++i){ 99 now[i].l = read(); 100 now[i].r = read(); 101 now[i].ind = i; 102 } 103 sort(now + 1 , now + Q + 1); 104 for(int i = 1 ; i <= Q ; ++i){ 105 for(int j = now[i - 1].r + 1 ; j <= now[i].r ; ++j){ 106 modify(1 , 1 , N , appear[num[j]] + 1 , j , num[j]); 107 appear[num[j]] = j; 108 } 109 ans[now[i].ind] = query(1 , 1 , N , now[i].l , now[i].r); 110 } 111 for(int i = 1 ; i <= Q ; ++i) 112 printf("%lld " , ans[i]); 113 return 0; 114 }
以上是关于SPOJ1557 GSS2 Can you answer these queries II 线段树的主要内容,如果未能解决你的问题,请参考以下文章
@spoj - gss2@ Can you answer these queries II
SPOJ GSS2 - Can you answer these queries II(线段树 区间修改+区间查询)(后缀和)
SPOJ - GSS2Can you answer these queries II(线段树)
BZOJ2482[Spoj1557] Can you answer these queries II 线段树