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分别表示以左端点为起始点,以右端点为起始点以及该区间内的最大的连续长度,更新时通过两个子区间相接的地方是否相同分不同的情况进行讨论。

#include <cstdio>
#include <algorithm>
using namespace std; const int MAXN = ; class SegNode {
public:
int L, R;
int l_value, r_value, value;
int is_same;
} node[ * MAXN]; int num[MAXN]; class SegTree {
public:
void log(int idx) {
printf("%d: ", idx);
for (int i = node[idx].L; i <= node[idx].R; i++)
printf("%d ", num[i]);
printf("(%d %d %d %d)\n", node[idx].l_value, node[idx].r_value, node[idx].value, node[idx].is_same);
}
void build(int root, int L, int R) { node[root].L = L;
node[root].R = R; if (L == R) {
// leaf
node[root].l_value = ;
node[root].r_value = ;
node[root].value = ;
node[root].is_same = ;
} else {
// non leaf
int M = (L + R) / ;
if (L <= M) {
build( * root, L, M);
}
if (M + <= R) {
build( * root + , M + , R);
}
if (num[node[ * root].R] == num[node[ * root + ].L]) {
node[root].l_value = node[ * root].l_value + node[ * root].is_same * node[ * root + ].l_value;
node[root].r_value = node[ * root + ].r_value + node[ * root + ].is_same * node[ * root].r_value;
node[root].value = max(max(node[ * root].value, node[ * root + ].value), node[ * root].r_value + node[ * root + ].l_value);
node[root].is_same = node[ * root].is_same & node[ * root + ].is_same;
} else {
node[root].l_value = node[ * root].l_value;
node[root].r_value = node[ * root + ].r_value;
node[root].value = max(node[ * root].value, node[ * root + ].value);
node[root].is_same = ;
}
//log(root);
}
}
int query(int root, int L, int R, int k) {
if (L <= node[root].L && R >= node[root].R) {
if (k == ) return node[root].value;
else if (k == ) return node[root].l_value;
else return node[root].r_value;
} if (L > node[root].R || R < node[root].L) {
return ;
} int M = (node[root].L + node[root].R) / ;
if (R <= M) {
return query( * root, L, R, k);
} else if (L > M) {
return query( * root + , L, R, k);
} else {
if (num[node[ * root].R] == num[node[ * root + ].L]) {
if (k == ) {
int res = ;
res = max(query( * root, L, R, ), query( * root + , L, R, ));
res = max(res, query( * root, L, R, ) + query( * root + , L, R, ));
return res;
} else if (k == ) {
int res = query( * root, L, R, );
if (node[ * root].is_same) res += query( * root + , L, R, );
return res;
} else {
int res = query( * root + , L, R, );
if (node[ * root + ].is_same) res += query( * root, L, R, );
return res;
}
} else {
if (k == ) {
return max(query( * root, L, R, ), query( * root + , L, R, ));
} else if (k == ) {
return query( * root, L, R, );
} else {
return query( * root + , L, R, );
}
}
}
}
} tree; int main() {
int n, q;
while (scanf("%d%d", &n, &q) && n) {
for (int i = ; i <= n; i++)
scanf("%d", &num[i]);
tree.build(, , n);
while (q--) {
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", tree.query(, l, r, ));
}
}
}

由这题想到了最大连续子段和这个问题,常见的解法是动态规划解法,算法课上讲了一个分治的解法,将整段分成左右两半,然后在中间点处向左和向右遍历,寻找最长的连续段,算法复杂度分析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]小的数量。

#include <cstdio>
#include <cstring>
using namespace std; const int MAXA = ;
const int MAXN = ; int c[MAXA];
int a[MAXN];
int left[MAXN], right[MAXN]; int lowbit(int x) {
return x & (-x);
} void insert(int i, int x) {
while (i < MAXA) {
c[i] += x;
i += lowbit(i);
}
} int query(int i) {
int res = ;
while (i > ) {
res += c[i];
i -= lowbit(i);
}
return res;
} int main() {
int T;
scanf("%d", &T);
while (T--) {
int n;
scanf("%d", &n);
for (int i = ; i < n; i++)
scanf("%d", &a[i]);
memset(c, , sizeof(c));
for (int i = ; i < n; i++) {
left[i] = query(a[i]);
insert(a[i], );
}
memset(c, , sizeof(c));
for (int i = n - ; i >= ; i--) {
right[i] = query(a[i]);
insert(a[i], );
}
long long ans = ;
for (int i = ; i < n; i++) {
ans += (long long)left[i] * (n - - i - right[i]);
ans += (i - left[i]) * (long long)right[i];
}
printf("%lld\n", ans);
}
}

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. 暑假集训(5)第一弹——— Super Jumping! Jumping! Jumping!(hdu1087)

    题意概括:在上次与娑殚的三次博弈中,你们都取得了胜利.便向娑殚提出要求,借助他的力量,传送到一个安全的地方. 你们的愿望达成了,不过,你和小A似乎失散了. 街上人来人往的特别热闹,每一个人的脸上都洋溢 ...

  2. UVaOJ 120 - Stacks of Flapjacks

    120 - Stacks of Flapjacks 题目看了半天......英语啊!!! 好久没做题...循环输入数字都搞了半天...罪过啊!!! 还是C方便一点...其实C++应该更方便的...C+ ...

  3. 创建型模式——Abstract Factory

    1.意图 提供一个创建一系列相关或相互依赖的接口,而无需指定它们具体的类. 2.结构 3.参与者 AbstractFactory声明一个创建抽象产品对象的操作接口 ConcreteFactory实现创 ...

  4. 屏蔽ubuntu桌面鼠标右键以及Ctrl Alt F*

    1.屏蔽右键: xmodmap -e "pointer = 1 2 99"xmodmap -e 'pointer = 1 2 0 4 5 6 7 8 9' #xmodmap -e ...

  5. makefile:4: *** missing separator. Stop.

    今天在编写蜂鸣器的驱动程序时,makefile文件是这样: CROSS=arm-linux- all: beep beep: beep.c $(CROSS)gcc -o beep beep.c $(C ...

  6. hdu 4641 K-string SAM的O(n^2)算法 以及 SAM+并查集优化

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=4641 题意:有一个长度为n(n < 5e4)的字符串,Q(Q<=2e5)次操作:操作分为:在末 ...

  7. (转载)Cocos2dx-OpenGL ES 2.0教程:你的第一个三角形(1)

    前言 在本系列教程中,我会以当下最流行的2D引擎Cocos2D-X为基础,介绍OpenGL ES 2.0的一些基本用法.本系列教程的宗旨是OpenGL扫盲,让大家在使用Cocos2D-X过程中,知其然 ...

  8. C# Windows - TextBox 控件

    .NET Framework内置了两个基本控件来提取用户输入的文本: TextBox和RichTextBox.这两个控件都派生于基类TextBoxBase,而TextBoxBase派生于Control ...

  9. 进入 App Store 打分

    很多用户用了好软件后忘记或嫌麻烦而不去 App Store 进行打分评星,为此开发者可以在应用中加入打分按钮,点击后直接跳转到 App Store 的评分界面. App Store 上评论的链接地址是 ...

  10. 在树莓派上 搭建sqlite数据库

    最近找工作需要学习一些数据库方面的知识,所以就在实验室的树莓派上准备装个数据库试试,刚开始准备装一个mysql数据库,出现了很多问题,放弃了,后来查了一些资料原来还有很多可以用的小巧实用的数据库,sq ...