(线段树区间合并)UVA 11235 - Frequent values

题意:

一个数列,多次查询L到R最多连续相同数字的数量。

分析:

显然区间合并。不过还就没写了,都有点忘了。

不过回忆一下,push_down还是写对了。

不过WA了,后来仔细想一想,光查询光用已经维护的答案还不够,还需要在query的时候再合并一下,才能更新出正确的答案。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 #include <vector>
 6
 7
 8 using namespace std;
 9
10 const int inf = 0x3f3f3f3f;
11 const int maxn = 100010;
12
13 struct Node {
14     int left, right;
15     int llen, rlen, zlen;
16     int lval, rval;
17 } node[maxn << 2];
18
19
20
21 void push_up(int n) {
22     node[n].llen = node[n << 1].llen;
23     node[n].lval = node[n << 1].lval;
24     node[n].rlen = node[n << 1 | 1].rlen;
25     node[n].rval = node[n << 1 | 1].rval;
26     if(node[n << 1].llen == node[n << 1].right - node[n << 1].left + 1 && node[n << 1].rval == node[n << 1 | 1].lval) {
27         node[n].llen += node[n << 1 | 1].llen;
28     }
29     if(node[n << 1 | 1].rlen == node[n << 1 | 1].right - node[n << 1 | 1].left + 1 && node[n << 1].rval == node[n << 1 | 1].lval) {
30         node[n].rlen +=  node[n << 1].rlen;
31     }
32     node[n].zlen = max(node[n << 1].zlen, node[n << 1 | 1].zlen);
33     if(node[n << 1].rval == node[n << 1 | 1].lval) {
34         node[n].zlen = max(node[n].zlen, node[n << 1].rlen + node[n << 1 | 1].llen);
35     }
36 }
37
38 void build(int n, int left, int right) {
39     node[n].left = left;
40     node[n].right = right;
41     if(left == right) {
42         scanf("%d", &node[n].lval);
43         node[n].rval = node[n].lval;
44         node[n].llen = node[n].rlen = node[n].zlen = 1;
45         return;
46     }
47     int mid = (left + right) >> 1;
48     build(n << 1, left, mid);
49     build(n << 1 | 1, mid + 1, right);
50     push_up(n);
51 }
52
53
54 int query(int n, int left, int right) {
55     if(node[n].left == left && node[n].right == right) {
56         return node[n].zlen;
57     }
58 //    printf("%d %d\n", node[n].left, node[n].right);
59     int mid = (node[n].left + node[n].right) >> 1;
60     int maxs = -1;
61     if(mid >= right)maxs = max(maxs, query(n << 1, left, right));
62     else if(mid < left)maxs = max(maxs, query(n << 1 | 1, left, right));
63     else {
64         int s = query(n << 1, left, mid);
65         int t = query(n << 1 | 1, mid + 1, right);
66         maxs = max(s, t);
67         int ls = min(node[n << 1].rlen, mid - left + 1);
68         int rs = min(node[n << 1 | 1].llen, right - mid);
69         if(node[n << 1].rval == node[n << 1 | 1].lval) {
70             maxs = max(maxs, ls + rs);
71         }
72     }
73 //    printf("--%d %d %d\n", node[n].left, node[n].right, maxs);
74     return maxs;
75 }
76
77 int main() {
78 #ifndef ONLINE_JUDGE
79 //    freopen("1.in", "r", stdin);
80 //    freopen("1.out", "w", stdout);
81 #endif
82     int n, q;
83     while(~scanf("%d", &n) && n) {
84         scanf("%d", &q);
85         build(1, 1, n);
86 //        for(int i = 1; i <= 250; i++) {
87 //            printf("%d %d %d %d %d\n", node[i].left, node[i].right, node[i].llen, node[i].rlen, node[i].zlen);
88 //        }
89         while(q--) {
90             int l, r;
91             scanf("%d%d", &l, &r);
92             printf("%d\n", query(1, l, r));
93 //            puts("");
94         }
95     }
96     return 0;
97
98 }
时间: 2024-10-12 22:46:09

(线段树区间合并)UVA 11235 - Frequent values的相关文章

uva 11235 - Frequent values(RMQ)

题目链接:uva 11235 - Frequent values 题目大意:给定一个非降序的整数数组,要求计算对于一些询问(i,j),回答ai,ai+1,-,aj中出现最多的数出现的次数. 解题思路:因为序列为非降序的,所以相同的数字肯定是靠在一起的,所以用o(n)的方法处理处每段相同数字的区间.然后对于每次询问: num[i]=num[j]:j?i+1 numi≠numj:max(RMQ(righti+1,reftj?1),max(righti?i+1,j?leftj+1)) #include

HDU 3911 Black And White(线段树区间合并)

Problem Description There are a bunch of stones on the beach; Stone color is white or black. Little Sheep has a magic brush, she can change the color of a continuous stone, black to white, white to black. Little Sheep like black very much, so she wan

HDU 3308 LCIS (线段树区间合并)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[mid + 1] > a[mid],写的细心点就好了. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int MAXN = 1

HDU 5316 Magician(线段树区间合并入门)

本文纯属原创,转载请注明出处谢谢.http://blog.csdn.net/zip_fan. 题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5316 Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Fantasy magicians usually gain their ability

poj3667 线段树 区间合并

1 //Accepted 3728 KB 1079 ms 2 //线段树 区间合并 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <cmath> 8 #include <algorithm> 9 using namespace std; 10 /** 11 * This is a document

hdu3911 线段树 区间合并

1 //Accepted 3911 750MS 9872K 2 //线段树 区间合并 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <cmath> 8 #include <algorithm> 9 using namespace std; 10 /** 11 * This is a documen

线段树 区间合并

poj3667 Hotel 区间合并入门题,照着代码打的, 题意:1 a:询问是不是有连续长度为a的空房间,有的话住进最左边       2 a b:将[a,a+b-1]的房间清空思路:记录区间中最长的空房间,开三个数组,msum[rt]表示节点rt内连续的1的个数的最大值,lsum[rt]表示从节点rt左端点开始连续1的个数,rsum[rt]表示从节点rt右端点开始连续1的个数..线段树操作:update:区间替换 query:询问满足条件的最左端点 1 #include<iostream>

【BZOJ3638】Cf172 k-Maximum Subsequence Sum 线段树区间合并(模拟费用流)

[BZOJ3638]Cf172 k-Maximum Subsequence Sum Description 给一列数,要求支持操作: 1.修改某个数的值 2.读入l,r,k,询问在[l,r]内选不相交的不超过k个子段,最大的和是多少.1 ≤ n ≤ 105,1 ≤ m ≤ 105,1 ≤ l ≤ r ≤ n, 1 ≤ k ≤ 20 Sample Input 9 9 -8 9 -1 -1 -1 9 -8 9 3 1 1 9 1 1 1 9 2 1 4 6 3 Sample Output 17 25

HDU 3308 LCIS(最长连续上升子序列)(线段树区间合并)

题意:给你n个整数,有两种操作,U A B把第A个数变成B,Q A B查询区间[A,B]的最长连续上升序列. 思路:还是查询和更新操作,而且也是询问区间中满足条件的连续最长区间 ,所以是线段树区间合并类型的题,通法是开三棵线段树,一个记录此区间内的LCIS的最长长度,一个记录从左边第一个数开始的LCIS长度,另一个记录从右边最后一个数结尾的LCIS长度.然后试图找到父亲与儿子关系维护的递推关系式就好 本题中的递推关系是: 1. 左儿子最右边的值 < 右儿子最左边的值 lmx = (左儿子的lmx

POJ 3667 Hotel (初遇线段树区间合并)

题意: 有一个线段,从1到n,下面m个操作,操作分两个类型,以1开头的是查询操作,以2开头的是更新操作 1 w 表示在总区间内查询一个长度为w的可用区间并且要最靠左,能找到的话返回这个区间的左端点并占用了这个区间,找不到返回0 2 a len , 表示从单位a开始,清除一段长度为len的区间(将其变为可用,不被占用),不需要输出. 思路: 这是第一次遇到线段树区间合并的题目,写下感悟,还是对线段的更新和查询工作,但是查询的对象的性质已经不像单点那样,查询的是某个线段的最大可用区间是多少,还要一并