线段树 点更新区间查询 配题(HDU 5172)

使用线段树对连续数据进行查询。查询的时间复杂度为O\left ( logn \right )

思想:对一个区间进行维护,父亲区间的信息,是左右子区间的信息综合。当子信息变更的时候需要去,同步更新父亲区间信息。

配题:HDU(5172)

题意简单:判断一段区间是否为1~b-a+1的全排列:

  • 区间内的数字加和为1~b-a+1(等差数列求和)
  • 区间内不能有重复的数字

解决方案:

  • 第一个问题可以通过预先存储前缀和来解决,O\left ( 1 \right )的时间就能去判断
  • 开一个数组,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;
}
发布了331 篇原创文章 · 获赞 135 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/Triple_WDF/article/details/102802254