hdu1698

http://www.notonlysuccess.com/index.php/segment-tree-complete/

hdu1698

#include <iostream>
#include <stdio.h>

using namespace std;

const int maxn = 111111;
int a[maxn];
int tree[maxn<<2];//线段树的每一个叶子节点就是a中的元素,还有其他的非叶子节点,应该需要2*maxn+1个元素
int col[maxn<<2];//如果当前节点有标记,就要先更新当前节点,并把标记传给孩子

void pushUp(int ind) {
	tree[ind] = tree[2*ind] + tree[2*ind+1];
}

void pushDown(int ind, int m) {
	if(col[ind]) {
		col[2*ind] = col[2*ind + 1] = col[ind];
		tree[2*ind] = col[ind] * (m - m/2);
		tree[2*ind + 1] = col[ind] * m/2;
		col[ind] = 0;
	}
}

void buildTree(int left, int right, int ind) {//找到叶子节点相应的位置, ind是这个节点的编号//left 和 right是这个节点所对应的范围
	if (left == right) {
		tree[ind] = 1;
		col[ind] = 0;
		return;
	}

	int mid = (left + right)/2;
	buildTree(left, mid, 2*ind);
	buildTree(mid+1, right, 2*ind + 1);
	pushUp(ind);

}


void update(int beg,int end ,int value, int left, int right, int ind) {
	if(beg <=left && end >= right) {//因为pushDown会更新孩子节点,所以到达这个节点后,已经是最新的值了,不需要再更新了
		col[ind] = value;
		tree[ind] = value*(right - left + 1);
		return;
	}

	pushDown(ind, right - left + 1);//把标记传给孩子节点,并更新孩子节点的值

	int mid = (left + right) / 2;
	if (mid >=beg)
		update(beg,end, value, left, mid, 2*ind);
	if (mid < end)
		update(beg,end,value, mid + 1, right, 2*ind+1);

	pushUp(ind);
}


int main() {
	int t,n, m;
	scanf("%d", &t);

	for (int i = 0; i < t ; ++i)
	{
		
		scanf("%d%d", &n, &m);
		
		buildTree(1,n, 1);

		while(m--) {
			int a, b, c;
			scanf("%d%d%d", &a, &b, &c);
			update(a,b,c,1,n,1);
		}
		printf("Case %d: The total value of the hook is %d.\n",t+1 , tree[1]);
	}
}


poj2528

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
 
const int maxn = 11111;
bool hash[maxn];
int li[maxn] , ri[maxn];
int X[maxn*3];
int col[maxn<<4];
int cnt;
 
void PushDown(int rt) {
	if (col[rt] != -1) {
		col[rt<<1] = col[rt<<1|1] = col[rt];
		col[rt] = -1;
	}
}
void update(int L,int R,int c,int l,int r,int rt) {
	if (L <= l && r <= R) {
		col[rt] = c;
		return ;
	}
	PushDown(rt);//对当前节点要往下传递
	int m = (l + r) >> 1;
	if (L <= m) update(L , R , c , lson);
	if (m < R) update(L , R , c , rson);
}
void query(int l,int r,int rt) {
	if (col[rt] != -1) {
		if (!hash[col[rt]]) cnt ++;
		hash[ col[rt] ] = true;
		return ;
	}
	if (l == r) return ;
	int m = (l + r) >> 1;
	query(lson);
	query(rson);
}
int Bin(int key,int n,int X[]) {
	int l = 0 , r = n - 1;
	while (l <= r) {
		int m = (l + r) >> 1;
		if (X[m] == key) return m;
		if (X[m] < key) l = m + 1;
		else r = m - 1;
	}
	return -1;
}
int main() {//求得有多少海报露在外面,不一定要完全露
	int T , n;
	scanf("%d",&T);
	while (T --) {
		scanf("%d",&n);
		int nn = 0;
		for (int i = 0 ; i < n ; i ++) {
			scanf("%d%d",&li[i] , &ri[i]);
			X[nn++] = li[i];
			X[nn++] = ri[i];
		}
		sort(X , X + nn);
		int m = 1;
		for (int i = 1 ; i < nn; i ++) {//去除重复的
			if (X[i] != X[i-1]) X[m ++] = X[i];
		}
		for (int i = m - 1 ; i > 0 ; i --) {//添加中间的值
			if (X[i] != X[i-1] + 1) X[m ++] = X[i-1] + 1;
		}
		sort(X , X + m);
		memset(col , -1 , sizeof(col));
		for (int i = 0 ; i < n ; i ++) {
			int l = Bin(li[i] , m , X);//二分查找,用次序替代大数
			int r = Bin(ri[i] , m , X);
			update(l , r , i , 0 , m , 1);
		}
		cnt = 0;
		memset(hash , false , sizeof(hash));
		query(0 , m , 1);
		printf("%d\n",cnt);
	}
	return 0;
}

2)在所有不大于30000的自然数范围内讨论一个问题:已知n条线段,把端点依次输入给你,然后有m(≤30000)个询问,每个询问输入一个点,要求这个点在多少条线段上出现过。

[问题分析]

在这个问题中,我们可以直接对问题处理的区间建立线段树,在线段树上维护区间被覆盖的次数。将n条线段插入线段树,然后对于询问的每个点,直接查询被覆盖的次数即可。

但是我们在这里用这道题目,更希望能够说明一个问题,那就是这道题目完全可以不用线段树。我们将每个线段拆成(L,+1),(R+1,-1)的两个事件点,每个询问点也在对应坐标处加上一个询问的事件点,排序之后扫描就可以完成题目的询问。我们这里讨论的问题是一个离线的问题,因此我们也设计出了一个很简单的离线算法。线段树在处理在线问题的时候会更加有效,因为它维护了一个实时的信息。

http://dongxicheng.org/structure/segment-tree/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值