Frequent values

题意是不同颜色区间首尾相接,询问一个区间内同色区间的最长长度。

网上流行的做法,包括翻出来之前POJ的代码也是RMQ做法,对于序列上的每个数,记录该数向左和向右延续的最远位置,那么对于一个查询Q(L, R),它的答案就分成了三种情况right(L) - L,R - left(R)以及Q(L+right(L),R-left(R))。

这里给出一个线段树做法,在线段树的节点上维护3个量:l_value, r_value, value分别表示以左端点为起始点,以右端点为起始点以及该区间内的最大的连续长度,更新时通过两个子区间相接的地方是否相同分不同的情况进行讨论。

  1. #include <cstdio>
  2. #include <algorithm>
  3. using namespace std;
  4.  
  5. const int MAXN = ;
  6.  
  7. class SegNode {
  8. public:
  9. int L, R;
  10. int l_value, r_value, value;
  11. int is_same;
  12. } node[ * MAXN];
  13.  
  14. int num[MAXN];
  15.  
  16. class SegTree {
  17. public:
  18. void log(int idx) {
  19. printf("%d: ", idx);
  20. for (int i = node[idx].L; i <= node[idx].R; i++)
  21. printf("%d ", num[i]);
  22. printf("(%d %d %d %d)\n", node[idx].l_value, node[idx].r_value, node[idx].value, node[idx].is_same);
  23. }
  24. void build(int root, int L, int R) {
  25.  
  26. node[root].L = L;
  27. node[root].R = R;
  28.  
  29. if (L == R) {
  30. // leaf
  31. node[root].l_value = ;
  32. node[root].r_value = ;
  33. node[root].value = ;
  34. node[root].is_same = ;
  35. } else {
  36. // non leaf
  37. int M = (L + R) / ;
  38. if (L <= M) {
  39. build( * root, L, M);
  40. }
  41. if (M + <= R) {
  42. build( * root + , M + , R);
  43. }
  44. if (num[node[ * root].R] == num[node[ * root + ].L]) {
  45. node[root].l_value = node[ * root].l_value + node[ * root].is_same * node[ * root + ].l_value;
  46. node[root].r_value = node[ * root + ].r_value + node[ * root + ].is_same * node[ * root].r_value;
  47. node[root].value = max(max(node[ * root].value, node[ * root + ].value), node[ * root].r_value + node[ * root + ].l_value);
  48. node[root].is_same = node[ * root].is_same & node[ * root + ].is_same;
  49. } else {
  50. node[root].l_value = node[ * root].l_value;
  51. node[root].r_value = node[ * root + ].r_value;
  52. node[root].value = max(node[ * root].value, node[ * root + ].value);
  53. node[root].is_same = ;
  54. }
  55. //log(root);
  56. }
  57. }
  58. int query(int root, int L, int R, int k) {
  59. if (L <= node[root].L && R >= node[root].R) {
  60. if (k == ) return node[root].value;
  61. else if (k == ) return node[root].l_value;
  62. else return node[root].r_value;
  63. }
  64.  
  65. if (L > node[root].R || R < node[root].L) {
  66. return ;
  67. }
  68.  
  69. int M = (node[root].L + node[root].R) / ;
  70. if (R <= M) {
  71. return query( * root, L, R, k);
  72. } else if (L > M) {
  73. return query( * root + , L, R, k);
  74. } else {
  75. if (num[node[ * root].R] == num[node[ * root + ].L]) {
  76. if (k == ) {
  77. int res = ;
  78. res = max(query( * root, L, R, ), query( * root + , L, R, ));
  79. res = max(res, query( * root, L, R, ) + query( * root + , L, R, ));
  80. return res;
  81. } else if (k == ) {
  82. int res = query( * root, L, R, );
  83. if (node[ * root].is_same) res += query( * root + , L, R, );
  84. return res;
  85. } else {
  86. int res = query( * root + , L, R, );
  87. if (node[ * root + ].is_same) res += query( * root, L, R, );
  88. return res;
  89. }
  90. } else {
  91. if (k == ) {
  92. return max(query( * root, L, R, ), query( * root + , L, R, ));
  93. } else if (k == ) {
  94. return query( * root, L, R, );
  95. } else {
  96. return query( * root + , L, R, );
  97. }
  98. }
  99. }
  100. }
  101. } tree;
  102.  
  103. int main() {
  104. int n, q;
  105. while (scanf("%d%d", &n, &q) && n) {
  106. for (int i = ; i <= n; i++)
  107. scanf("%d", &num[i]);
  108. tree.build(, , n);
  109. while (q--) {
  110. int l, r;
  111. scanf("%d%d", &l, &r);
  112. printf("%d\n", tree.query(, l, r, ));
  113. }
  114. }
  115. }

由这题想到了最大连续子段和这个问题,常见的解法是动态规划解法,算法课上讲了一个分治的解法,将整段分成左右两半,然后在中间点处向左和向右遍历,寻找最长的连续段,算法复杂度分析T(n)=2T(n/2)+O(n),因此复杂度是O(nlgn)。然而可以使用上面的思路进行维护,维护一个以左端点为起点的最长连续子段,该子段记作left(root),讲root分成L,R,那么left(root)=max{left(L), sum(L)+left(R)},这样查询中点mid的最优值就可以用right(L)+left(R)来替代了,复杂度为O(1),最后也就可以做到复杂度为O(nlgn)的最大子段和的分治算法了。

Ping pong

题意是各个序列,统计这样的三元组(a,b,c),满足条件idx(a)<idx(b)<idx(c),且a<b<c或者a>b>c的数量。

做法是用树状数组统计出给定一个索引i,i左侧比a[i]小的数量,以及右侧比a[i]小的数量,用左侧比a[i]小的数量乘上右侧比a[i]大的数量,以及左侧比a[i]大的数量乘上右侧比a[i]小的数量。

  1. #include <cstdio>
  2. #include <cstring>
  3. using namespace std;
  4.  
  5. const int MAXA = ;
  6. const int MAXN = ;
  7.  
  8. int c[MAXA];
  9. int a[MAXN];
  10. int left[MAXN], right[MAXN];
  11.  
  12. int lowbit(int x) {
  13. return x & (-x);
  14. }
  15.  
  16. void insert(int i, int x) {
  17. while (i < MAXA) {
  18. c[i] += x;
  19. i += lowbit(i);
  20. }
  21. }
  22.  
  23. int query(int i) {
  24. int res = ;
  25. while (i > ) {
  26. res += c[i];
  27. i -= lowbit(i);
  28. }
  29. return res;
  30. }
  31.  
  32. int main() {
  33. int T;
  34. scanf("%d", &T);
  35. while (T--) {
  36. int n;
  37. scanf("%d", &n);
  38. for (int i = ; i < n; i++)
  39. scanf("%d", &a[i]);
  40. memset(c, , sizeof(c));
  41. for (int i = ; i < n; i++) {
  42. left[i] = query(a[i]);
  43. insert(a[i], );
  44. }
  45. memset(c, , sizeof(c));
  46. for (int i = n - ; i >= ; i--) {
  47. right[i] = query(a[i]);
  48. insert(a[i], );
  49. }
  50. long long ans = ;
  51. for (int i = ; i < n; i++) {
  52. ans += (long long)left[i] * (n - - i - right[i]);
  53. ans += (i - left[i]) * (long long)right[i];
  54. }
  55. printf("%lld\n", ans);
  56. }
  57. }

Frequent values && Ping pong的更多相关文章

  1. UVA - 11235 Frequent values

    2007/2008 ACM International Collegiate Programming Contest University of Ulm Local Contest Problem F ...

  2. HDU 2492 Ping pong (树状数组)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2492 Ping pong Problem Description N(3<=N<=2000 ...

  3. UVALive 4329 Ping pong

                                      Ping pong Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Fo ...

  4. poj 3368 Frequent values(RMQ)

    /************************************************************ 题目: Frequent values(poj 3368) 链接: http ...

  5. POJ 3928 Ping pong(树状数组)

                                                                          Ping pong Time Limit: 1000MS   ...

  6. LA4329 Ping pong(树状数组与组合原理)

    N (3N20000)ping pong players live along a west-east street(consider the street as a line segment). E ...

  7. H - Frequent values

    Problem F: Frequent values You are given a sequence of n integers a1 , a2 , ... , an in non-decreasi ...

  8. Ping pong

    Ping pong Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  9. POJ 3928 Ping pong

    题目链接:http://poj.org/problem?id=3928 乒乓比赛,有N个人参加,输入每个玩家的技能等级,对每个人设置一个特定ID和一个技能值,一场比赛需要两个选手和一个裁判,只有当裁判 ...

随机推荐

  1. jobs

    fg.bg.jobs.&.ctrl + z都是跟系统任务有关的,虽然现在基本上不怎么需要用到这些命令,但学会了也是很实用的一.& 最经常被用到这个用在一个命令的最后,可以把这个命令放到 ...

  2. linux与windows共享剪贴板(clipboard)

    linux与windows共享剪贴板(clipboard)的方法 先说两句废话,其实linux和windows之间不需要共享剪贴板,直接在putty中,按住SHIFT+鼠标选择就可以了. 但是作为一种 ...

  3. 【转】winform与web 按钮button去掉边框

    ref:http://blog.csdn.net/wangzh300/article/details/5264316 WinForm的话 设置Button属性的FlatStyle为Flat,并且设置F ...

  4. Android 核心组件 Activity 之下

    创建新的Activity的方式: 1. 在相应的文件下 Ctrl + N  (Eclipse, Android中不知道是不是) 2. 创建类,继承自Activity或者Activity的子孙类, 并在 ...

  5. 判断IE版本的语句 [if lte IE 6]...[endif]

    <!–[if lte IE 6]>……<![endif]–>Ite:less than or equal to意思是小于或等于IE6浏览器,用于IE浏览器的条件注释,常用于CS ...

  6. 写了个Linux包过滤防火墙

    花几天写了个so easy的Linux包过滤防火墙,估计实际意义不是很大.防火墙包括用户态执行程序和内核模块,内核模块完全可以用iptable代替.由于在编写的过程一开始写的是内核模块所以就直接用上来 ...

  7. php计算时间差的方法

    一个简单的例子:计算借书的天数,根据每天的日期进行计算. (1) 有数据库的情况      MSSQL可以使用触发器!用专门计算日期差的函数datediff()便可.    MYSQL那就用两个日期字 ...

  8. php curl 伪造IP来源的代码分享

    php curl 可以模仿用户登录,还可以模仿用户IP地址.伪造IP来源. 1,curl发出请求的文件fake_ip.php: <?php $ch = curl_init(); $url = & ...

  9. mysql 的 存储结构(储存引擎)

    1 MyISAM:这种引擎是mysql最早提供的.这种引擎又可以分为静态MyISAM.动态MyISAM 和压缩MyISAM三种:    静态MyISAM:如果数据表中的各数据列的长度都是预先固定好的, ...

  10. mac上xampp配置

    sudo su /Applications/XAMPP/xamppfiles/xampp security