线段数组 -以poj2777为例

线段树是一种用于区间查询和更新的数据结构,由Jon Louis Bentley于1977年发明。文章介绍了线段树的基本概念、空间和时间复杂度,并通过POJ2777染色板问题来阐述其应用,解决大规模数据下的高效查询需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线段树英语:Segment tree)是一种二叉树形数据结构,1977年由Jon Louis Bentley发明[1],用以储存区间线段,并且允许快速查询结构内包含某一点的所有区间。

一个包含{\displaystyle n}n个区间的线段树,空间复杂度为{\displaystyle O(n\log n)}O(n\log n),查询的时间复杂度则为{\displaystyle O(\log n+k)}{\displaystyle O(\log n+k)},其中{\displaystyle k}k是符合条件的区间数量。

此数据结构亦可推广到高维度。                                                                                                             

                                                                                                                                                                        --维基百科

简单来说,就是对于一个给定的数组,以它的所有元素作为叶子节点构建一棵二叉树,其父结点储存子节点的和(也可以储存其他东西,如最大最小值)。其目的就是为了能够快速查询某个区间的和(或者其他),并且在改变某个(某些)数组元素以后仍能快速查询。

构建过程是从根到叶子的。假定数组有六个元素[1, 3, 5, 7, 9, 11],那我们构建出来的线段数组应如下图。

此外,每个点还应该保留它的区间信息,代表是哪个区间的和。叶子节点的区间则是[n,n]。



该网页讲的已经比较清楚了,不再复述。https://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range/


下面题目

POJ2777 : http://poj.org/problem?id=2777

 【问题描述】一个有L个格子的染色板,每个格子编号为1,2,3……L,每个格子初始都染成了1号色。一共有T种不同的颜色,编号分别为1,2,3……T。可进行O次操作。对染色板的操作有2种。

 (1C(a,b,c) 意思是将染色板中编号为a~b的所有格子染成c号色(1≤a≤b≤L,1≤c≤T)

 2P(a,b)意思是查询染色板中编号为a~b的格子染成的颜色种数。(1≤a≤b≤L)


【输入】 第一行有三个正整数,分别为LTO.

接下来有O行,每行为C a b cP a b。(CP是字母,a,b,c均为正整数) 【输出】输出有若干行,分别回答输入中每个查询的结果。



【样例输入】

6 4 5

C 1 2 2

C 2 3 3

P 1 3

C 3 6 4

P 1 6

【样例输出】

2

3

【数据规模】

1≤L≤100,000 1≤T≤30 1≤O≤100,000

注意到L和O的给定范围很大(1 <= L, O <= 100000)而T的给定范围很小(<30)。用普通的方法做会超时,故用线段树组。

这里先贴代码,语言Java

import java.util.Scanner;

import javax.net.ssl.SSLContext;
import javax.print.attribute.standard.RequestingUserName;

import org.omg.CORBA.PUBLIC_MEMBER;
import org.omg.CORBA.ORBPackage.InconsistentTypeCode;

import javafx.stage.PopupWindow;

public class sgmTree {
	private int st[];
	private int num;
	private int temp;
	public sgmTree(int arr[], int n) {
		int x = (int)(Math.ceil(Math.log(n)/Math.log(2)));
		int max_size = (int)(2 * Math.pow(2, X) -1);
		st = new int[max_size];
		num = n;
	
	constructSTUtil(arr, 0, n-1, 0);
	}
	
	private int getMid(int ss, int se) {return ss + (se-ss)/2;}
	
	private int getSumUtil(int ss, int se, int qs, int qe, int si) {
		if(qs<=ss && se <= qe)
			return st[si];
		if(qs > se || qe < ss)
			return 0;
		int mid = getMid(ss, se);
		return (getSumUtil(ss, mid, qs, qe, 2*si+1) |
				getSumUtil(mid+1, se, qs, qe, 2*si+2));
	}
	
	private void updateValueUtil(int ss, int se, int i, int diff, int si) {
		if(i<ss || i>se)return;
		if(ss != se) {
			int mid = getMid(ss, se);
			updateValueUtil(ss, mid, i, diff, 2*si+1);
			updateValueUtil(mid+1, se, i, diff, 2*si+2);
		}	
		if(ss == se) {
			temp = st[si];
			st[si] = diff;
		}
		else {
			if(((st[2*si+1] & temp) != 0) || (((st[2*si+2] & temp) != 0)))
				st[si] = diff | st[si];
			else {
				st[si] = diff | st[si];
				st[si] = st[si] & (~temp);
			}
				
		}
		return;
	}
	
	public void updateValue(int i, int value ) {
		if(i < 0 || i > num)return;
		updateValueUtil(0, num-1, i-1, (int)(Math.pow(2,value)), 0);
		return;
	}
	public int getSum(int qs, int qe) {
		if(qs < 1 || qe > num+1)return -1;
		int sum = getSumUtil(0, num-1, qs-1, qe-1, 0);
		int result = 0;
		while(sum != 0) {
			result++;
			sum -= sum & (-sum);
		}
		
		return result; 
	}
	
	public int constructSTUtil(int array[], int ss, int se, int si) {
		if(ss == se) {
			st[si] = (int)Math.pow(2, array[ss]);
			return st[si];
		}
		else {
			int mid = getMid(ss, se);
			st[si] = (constructSTUtil(array, ss, mid, 2*si+1) |
					constructSTUtil(array, mid + 1, se, 2*si+2));
			return st[si];
		}
		
	}
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		int L = input.nextInt();
		int T = input.nextInt();
		int O = input.nextInt();
		
		int[] arr = new int[L];
		for(int i = 0; i<L; i++) {
			arr[i] = 1;
		}
		sgmTree tree = new sgmTree(arr, 5);
		
		while(O != 0) {
			char action = input.next().charAt(0);
			if(action == 'C') {
				int a = input.nextInt();
				int b = input.nextInt();
				int c = input.nextInt();
				for(int i = a; i < b+1; i++) {
					tree.updateValue(i++, c);
				}
			}
			if(action == 'P') {
				int a = input.nextInt();
				int b = input.nextInt();
				System.out.println(tree.getSum(a, b));
			}
			O--;
		}
		input.close();
		
	}
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值