使用线段树对连续数据进行查询。查询的时间复杂度为。
思想:对一个区间进行维护,父亲区间的信息,是左右子区间的信息综合。当子信息变更的时候需要去,同步更新父亲区间信息。
配题:HDU(5172)
题意简单:判断一段区间是否为1~b-a+1的全排列:
- 区间内的数字加和为1~b-a+1(等差数列求和)
- 区间内不能有重复的数字
解决方案:
- 第一个问题可以通过预先存储前缀和来解决,的时间就能去判断
- 开一个数组,arr[i],表示与第 i 个数字相同,且最近一次出现的位置(1~i-1中与第 i 个数字一样且距离第 i 个数字位置更近的那个数字的位置),那么如果对于一个查询区间(a,b)如果在这个区间内,没有重复的数字,arr[i]在该区间上的最大值应该小于a
#include<iostream>
#include<cstring>
#include<cstdio>
#define L(x) x << 1
#define R(x) (x << 1) | 1
using namespace std;
const int maxn = 1000000 + 5;
int n, m;
long long int sum[maxn];
int pre[maxn];
struct NODE
{
int lft, rht;
int val;
int mid()
{
return (lft + rht) / 2;
}
};
NODE segment_tree[maxn*4];
int Max(int x, int y)
{
if (x > y) return x;
return y;
}
void build_segtree(int cur_index, int lft, int rht)
{
segment_tree[cur_index].lft = lft;
segment_tree[cur_index].rht = rht;
segment_tree[cur_index].val = 0;
if (lft != rht)
{
int mid = segment_tree[cur_index].mid();
build_segtree(L(cur_index), lft, mid);
build_segtree(R(cur_index), mid+1, rht);
}
}
void updata_segtree(int cur_index, int pos, int val)
{
int lft = segment_tree[cur_index].lft;
int rht = segment_tree[cur_index].rht;
if (lft == rht)
{
segment_tree[cur_index].val = val;
}
else
{
int mid = segment_tree[cur_index].mid();
if (pos <= mid) updata_segtree(L(cur_index), pos, val);
else updata_segtree(R(cur_index), pos, val);
segment_tree[cur_index].val = Max(segment_tree[L(cur_index)].val, segment_tree[R(cur_index)].val);
}
}
int query_segtree(int cur_index, int pos_lft, int pos_rht)
{
int lft = segment_tree[cur_index].lft;
int rht = segment_tree[cur_index].rht;
if (pos_lft <= lft && rht <= pos_rht)
{
return segment_tree[cur_index].val;
}
else
{
int mid = segment_tree[cur_index].mid();
int res1 = 0;
int res2 = 0;
if (pos_lft <= mid) res1 = query_segtree(L(cur_index), pos_lft, pos_rht);
if (pos_rht > mid) res2 = query_segtree(R(cur_index), pos_lft, pos_rht);
return Max(res1, res2);
}
}
int main()
{
while (~scanf("%d %d", &n, &m))
{
build_segtree(1, 1, n);
memset(pre, 0, sizeof(pre));
sum[0] = 0;
for (int i = 1; i <= n; i++)
{
int val;
int pre_id;
scanf("%d", &val);
sum[i] = sum[i-1] + val;
pre_id = pre[val];
pre[val] = i;
updata_segtree(1, i, pre_id);
}
for (int i = 1; i <= m; i++)
{
int a, b;
scanf("%d %d", &a, &b);
if (sum[b] - sum[a-1] != (b - a + 2)*(b - a + 1)/2)
{
printf("NO\n");
}
else
{
if (query_segtree(1, a, b) < a)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
}
}
}
return 0;
}
同时我还写了指针版本的线段树,但是超内存,但是每组数据之后我都清空了内存,但是还是不行超了大概几百KB,后来思考了一下,可能是指针本身就要占据4bit的内存,那么1000000*4bit = 500KB,每个指针结构体的内部还有两个指针结构体,总的指针需要占用500*3 = 1500KB,加上本来就需要使用的结构体的内存空间,就超了几百KB。下面的是指针版本的线段树代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
const int maxn = 1000000+5;
int n, m;
long long int sum[maxn];
int pre[maxn];
struct NODE
{
int lft, rht;
int val;
NODE* lson;
NODE* rson;
NODE(): lson(NULL), rson(NULL){}
int mid()
{
return (lft + rht) / 2;
}
};
int Max(int x, int y)
{
if (x > y) return x;
else return y;
}
void init_segment_tree(NODE* cur_node, int lft, int rht)
{
cur_node->lft = lft;
cur_node->rht = rht;
cur_node->val = 0;
if (lft != rht)
{
int mid = cur_node->mid();
cur_node->lson = new NODE;
cur_node->rson = new NODE;
init_segment_tree(cur_node->lson, lft, mid);
init_segment_tree(cur_node->rson, mid+1, rht);
}
}
void updata_segment_tree(NODE* cur_node, int pos, int val)
{
if (cur_node->lft == cur_node->rht)
{
cur_node->val = val;
return;
}
else
{
int mid = cur_node->mid();
if (pos < mid) updata_segment_tree(cur_node->lson, pos, val);
else updata_segment_tree(cur_node->rson, pos, val);
cur_node->val = Max(cur_node->lson->val, cur_node->rson->val);
return;
}
}
int query_segment_tree(NODE* cur_node, int lft, int rht)
{
if (lft <= cur_node->lft && cur_node->rht <= rht)
{
return cur_node->val;
}
else
{
int mid = cur_node->mid();
int res1=0, res2=0;
if (lft <= mid) res1 = query_segment_tree(cur_node->lson, lft, rht);
if (rht > mid) res2 = query_segment_tree(cur_node->rson, lft, rht);
return Max(res1, res2);
}
}
void delete_segment_tree(NODE* cur_node)
{
if (cur_node->lft == cur_node->rht)
{
delete cur_node;
return;
}
else
{
delete_segment_tree(cur_node->lson);
delete_segment_tree(cur_node->rson);
delete cur_node->lson;
delete cur_node->rson;
delete cur_node;
}
}
int main()
{
while (cin>> n>> m)
{
NODE* segment_tree = new NODE;
init_segment_tree(segment_tree, 1, n);
sum[0] = 0;
memset(pre, 0, sizeof(pre));
for (int i = 1; i <= n; i++)
{
int pre_id;
int val;
scanf("%d", &val);
sum[i] = sum[i-1] + val;
pre_id = pre[val];
pre[val] = i;
updata_segment_tree(segment_tree, i, pre_id);
}
for (int i = 1; i <= m; i++)
{
int a, b;
scanf("%d %d", &a, &b);
if (sum[b] - sum[a-1] != (b-a+2)*(b-a+1)/2)
{
cout<< "NO"<< endl;
}
else
{
int res = query_segment_tree(segment_tree, a, b);
if (res < a)
{
cout<< "YES"<< endl;
}
else
{
cout<< "NO"<< endl;
}
}
}
delete_segment_tree(segment_tree);
}
return 0;
}