您的位置:首页 > 其它

HDU 4638 - Group(树状数组 / 线段树)

2015-03-31 20:41 316 查看
#题目:

http://acm.hdu.edu.cn/showproblem.php?pid=4638

#题意:

给出n(1<=n<=100000)个数代表人的id(1-n), 有m个询问区间(x, y), 求出区间中分成多少组使得组和最大, 同一组内的id必须连续.

#思路:

题目转化:要使得和最大,应该尽可能的使得连续id的分成一组, 所以就变成了一个区间中连续id的区间.

树状数组.

初始化时记录a[i] 在数组中的位置pos[a[i]] = i.

从左到右扫描,当前为a[i], 先假设a[i]不与前面的任何数同一组,则将区间[1, i]都加1. 若pos[a[i] + 1] < i, 说明a[i]可以加入前面a[i]+1的那个区间中, 则区间[1,pos[a[i]+1] ] 减1, 对于pos[a[i] - 1] 同样操作.

边处理边询问, 若v[j].r == i 则得到答案.

AC.

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>

using namespace std;
const int maxn = 1e5+5;
struct node {
int l, r, id;
bool operator < (const node & A) const {
if(A.r == r) return l < A.l;
return r < A.r;
}
}Q;
vector<node> v;

int n, q;
int a[maxn], c[maxn], pos[maxn], ans[maxn];

int lowbit(int x)
{
return x&(-x);
}
void add(int i, int val)
{
while(i <= n) {
c[i] += val;
i += lowbit(i);
}
}
int sum(int x)
{
int s = 0;
while(x >= 1) {
s += c[x];
x -= lowbit(x);
}
return s;
}

void init()
{
//memset(a, 0, sizeof(a));
memset(c, 0, sizeof(c));
//memset(pos, 0, sizeof(pos));
//memset(ans, 0, sizeof(ans));
v.clear();
}

int main()
{
//freopen("in", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {

scanf("%d %d", &n, &q);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
pos[a[i]] = i;
}

v.clear();
for(int i = 1; i <= q; ++i) {
scanf("%d %d", &Q.l, &Q.r);
Q.id = i;
v.push_back(Q);
}

sort(v.begin(), v.end());
memset(c, 0, sizeof(c));

int j = 0;
for(int i = 1; i <= n; ++i) {
add(i, 1);

if(a[i] + 1 <= n && pos[a[i]+1] < i) {
add(pos[a[i]+1], -1);
}

if(a[i]-1 >= 1 && pos[a[i]-1] < i) {
add(pos[a[i]-1], -1);
}

while(v[j].r == i) {
ans[v[j].id] = sum(v[j].r) - sum(v[j].l-1);
j++;
}
}

for(int i = 1; i <= q; ++i) {
printf("%d\n", ans[i]);
}
}
return 0;
}


线段树. 单点更新, 成段求和.
AC.

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int sumv[maxn<<2];
int p[maxn], ans[maxn];

void update(int pos, int l, int r, int k, int v)
{
if(l == r) {
sumv[k] += v;
}
else {
int mid = (l+r)/2;
if(pos <= mid) update(pos, l, mid, k*2, v);
if(pos > mid) update(pos, mid+1, r, k*2+1, v);
sumv[k] = sumv[k*2] + sumv[k*2+1];
}
}
int query(int k, int l, int r, int x, int y)
{
if(l >= x && r <= y) return sumv[k];
else {
int ans = 0;
int mid = (l + r)/2;
if(x <= mid) ans += query(k*2, l, mid, x, y);
if(y > mid) ans += query(k*2+1, mid+1, r, x, y);
return ans;
}
}

struct node {
int l, r, id;
bool operator < (const node &A) const {
if(r == A.r) return l < A.l;
return r < A.r;
}
}Q;
vector<node> v;

int main()
{
//freopen("in", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {

int n, q;
scanf("%d %d", &n, &q);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
p[a[i]] = i;
}
v.clear();
for(int i = 0; i < q; ++i) {
scanf("%d %d", &Q.l, &Q.r);
Q.id = i;
v.push_back(Q);
}

sort(v.begin(), v.end());
memset(sumv, 0, sizeof(sumv));

int j = 0;
for(int i = 1; i <= n; ++i) {
update(i, 1, n, 1, 1);
if(a[i]+1<=n && p[a[i]+1]<i) {
update(p[a[i]+1], 1, n, 1, -1);
}
if(a[i]-1>=1 && p[a[i]-1]<i) {
update(p[a[i]-1], 1, n, 1, -1);
}
while(v[j].r == i) {
ans[v[j].id] = query(1, 1, n, v[j].l, v[j].r);
j++;
}
}
for(int i = 0; i < q; ++i) {
printf("%d\n", ans[i]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  HDU