原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=4638
Group
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 747 Accepted Submission(s): 405
Problem Description
There are n men ,every man has an ID(1..n).their ID is unique. Whose ID is i and i-1 are friends, Whose ID is i and i+1 are friends. These n men stand in line. Now we select an interval of men to make some group. K men in a group can create K*K value. The value of an interval is sum of these value of groups.
The people of same group's id must be continuous. Now we chose an interval of men and want to know there should be how many groups so the value of interval is max.
Input
First line is T indicate the case number.
For each case first line is n, m(1<=n ,m<=100000) indicate there are n men and m query.
Then a line have n number indicate the ID of men from left to right.
Next m line each line has two number L,R(1<=L<=R<=n),mean we want to know the answer of [L,R].
For each case first line is n, m(1<=n ,m<=100000) indicate there are n men and m query.
Then a line have n number indicate the ID of men from left to right.
Next m line each line has two number L,R(1<=L<=R<=n),mean we want to know the answer of [L,R].
Output
For every query output a number indicate there should be how many group so that the sum of value is max.
Sample Input
1 5 2 3 1 2 5 4 1 5 2 4
Sample Output
1 2
题意:任意一个1~n的排列,每次询问一段区间,问该区共有多少组包含连续数字的数组。
思路:此题如果将询问按照右端点从小到大排列,然后将所有的连续的数字组数合并到最右的数字,再用树状数组来维护,就非常简单了。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAX 100010
int n, m, c[MAX], a[MAX], pos[MAX];
struct L {
int l, r, id;
int ans;
bool operator <(L othr) const {
return id < othr.id;
}
} query[MAX];
int cmp(L x, L y) {
return x.r < y.r;
}
inline int lowbit(int x) {
return x & (-x);
}
void add(int i, int val) {
while (i <= MAX) {
c[i] += val;
i += lowbit(i);
}
}
int getsum(int i) {
int s = 0;
while (i >= 1) {
s += c[i];
i -= lowbit(i);
}
return s;
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
memset(c, 0, sizeof(c));
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", a + i);
pos[a[i]] = i; //保存每个数字出现的地址
}
for (int i = 0; i < m; i++) {
scanf("%d%d", &query[i].l, &query[i].r);
query[i].id = i;
}
sort(query, query + m, cmp); //按照区间的右端点排列
int cur = 0;
for (int i = 1; i <= n; i++) {
add(i, 1); //将该位置取1
if (a[i] > 1 && pos[a[i] - 1] < i) add(pos[a[i] - 1], -1);
if (a[i] < n && pos[a[i] + 1] < i) add(pos[a[i] + 1], -1);
//如果之前有一个比a[i]相邻的数,则将该位1的大小转移到右边i的位置
while (query[cur].r == i && cur < m) { //如果刚好更新到询问的节点
//cout<<i<<' '<<getsum(query[p].r)<<' '<<getsum(query[p].l)<<endl;
query[cur].ans = getsum(query[cur].r) - getsum(query[cur].l - 1);
cur++;
}
}
sort(query, query + m); //按照原来的顺序排序输出
for (int i = 0; i < m; i++) {
printf("%d\n", query[i].ans);
}
}
}