Count the Colors (线段树染色)

Painting some colored segments on a line, some previously painted segments may be covered by some the subsequent ones.

Your task is counting the segments of different colors you can see at last.

 

Input



The first line of each data set contains exactly one integer n, 1 <= n <= 8000, equal to the number of colored segments.

 

Each of the following n lines consists of exactly 3 nonnegative integers separated by single spaces:

x1 x2 c

x1 and x2 indicate the left endpoint and right endpoint of the segment, c indicates the color of the segment.

All the numbers are in the range [0, 8000], and they are all integers.

Input may contain several data set, process to the end of file.

 

Output



Each line‎输出的颜色索引应该包含一个颜色索引, 可以从顶部看到, 在此颜色的线段计数后, 他们应该根据颜色索引打印。‎

 

‎如果看不到某种颜色, 则不应打印。‎

Print a blank line after every dataset.

 

Sample Input



5
0 4 4
0 3 1
3 4 2
0 2 2
0 2 3
4
0 1 1
3 4 1
1 3 2
1 3 1
6
0 1 0
1 2 1
2 3 1
1 2 0
2 3 0
1 2 1

 

 

Sample Output



1 1
2 1
3 1

 

1 1

0 2
1 1

/*
  经典的线段树染色问题,成段更新懒标记。 
  这里考虑染色的片段,不是染色的结点。
*/   
#include<bits/stdc++.h>
using namespace std;
const int maxn=8010;
struct node
{
    int l,r;
    int color;
}tree[maxn<<2];
int color[maxn]; //存储所有颜色片段个数,为0代表没有该颜色。 
int temp;//用来存储上个颜色 
void push_down(int k)//下传更新 
{
	tree[k<<1].color=tree[k<<1|1].color=tree[k].color;
	tree[k].color=-2;//多种颜色 
} 
void build(int k,int l,int r)//建树 
{
	tree[k].l=l;
	tree[k].r=r;
	tree[k].color=-1;//代表没有颜色 
	if(l+1==r) return ;
	int mid = (l+r)/2;
	build(k<<1,l,mid);
	build(k<<1|1,mid,r);
}
void insert(int k,int l,int r,int c)
{
	if(l==r) return ;
	if(tree[k].color==c) return ;  
	if(l<=tree[k].l&&r>=tree[k].r)
	{
		tree[k].color=c;
		return ;
	} 
	if(tree[k].color>=0) push_down(k);//存在颜色,下传更新 
	int mid=(tree[k].l+tree[k].r)/2;
	if(r<=mid) insert(k<<1,l,r,c);
	else if(l>=mid) insert(k<<1|1,l,r,c);
	else{
		insert(k<<1,l,mid,c);
		insert(k<<1|1,mid,r,c);
	} 
	tree[k].color=-2;
}
void count(int k)//统计颜色的段数 
{
	if(tree[k].color==-1)
	{
		temp=-1;
		return ;
	} 
	if(tree[k].color!=-2)//纯色 
	{
		if(tree[k].color!=temp)//和上一个不同存入数组种 
		{
			color[tree[k].color]++;
			temp=tree[k].color;
		}
		return ;
    }
    if(tree[k].l+1!=tree[k].r)//递归求左儿子和右儿子 
	{
		count(k<<1);
		count(k<<1|1);
	} 
}
int main()
{
    int n,a,b,c;
    int Max;
    while(scanf("%d",&n)!=EOF)
    {
        build(1,0,8000);
        Max=0;
        while(n--)
        {
            scanf("%d%d%d",&a,&b,&c);
            insert(1,a,b,c);
            if(c>Max)Max=c;
        }//Max记录其中出现的最大颜色 
        temp=-1;//初始化为没有颜色 
        memset(color,0,sizeof(color));
        count(1);
        for(int i=0;i<=Max;i++)
            if(color[i])
			   printf("%d %d\n",i,color[i]);
        printf("\n");
    }
    return 0;
}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
抱歉,我之前的回答有误,感谢您指出。确实使用哈希表的解法还是 O(n^2) 的时间复杂度。下面提供一种使用线段树的解法,时间复杂度为 O(n*log(n))。 我们可以考虑对 b 数组进行处理,将其转化为前缀和形式。即,我们新建一个数组 s,s[i] 表示 b[0] + b[1] + ... + b[i],这样,对于任意的 i 和 j,我们可以计算出 b[i] + b[j] 的值,也就是 s[j] - s[i-1]。 接下来,我们可以遍历所有的 i 和 j,计算出 ai*aj 的值,然后在 s 数组中二分查找是否存在一个位置 k 使得 s[k] 的值等于 ai*aj。如果存在这样的 k,那么就说明存在一对满足条件的 (i, j)。 为了避免重复计算,我们可以在遍历 j 的时候,将之前已经计算过的 ai*aj 的值存储在一个 set 中。在计算新的 ai*aj 的值之前,我们可以先判断这个值是否已经在 set 中出现过了。 为了快速地进行二分查找,我们可以使用线段树来维护 s 数组。线段树上的每个节点表示 s 数组中某个区间的和,我们可以在构建线段树的时候,同时记录下每个节点对应的区间范围。这样,在查询的时候,我们只需要在线段树上进行二分查找即可。 以下是代码实现: ```python class SegmentTree: def __init__(self, data): self.data = data self.tree = [0] * (4*len(data)) self.build_tree(0, 0, len(data)-1) def build_tree(self, node, start, end): if start == end: self.tree[node] = self.data[start] else: mid = (start + end) // 2 left_child = 2*node + 1 right_child = 2*node + 2 self.build_tree(left_child, start, mid) self.build_tree(right_child, mid+1, end) self.tree[node] = self.tree[left_child] + self.tree[right_child] def query(self, node, start, end, target): if start == end: return start else: mid = (start + end) // 2 left_child = 2*node + 1 right_child = 2*node + 2 if target <= self.tree[left_child]: return self.query(left_child, start, mid, target) else: return self.query(right_child, mid+1, end, target-self.tree[left_child]) def update(self, node, start, end, index, value): if start == end: self.tree[node] = value else: mid = (start + end) // 2 left_child = 2*node + 1 right_child = 2*node + 2 if index <= mid: self.update(left_child, start, mid, index, value) else: self.update(right_child, mid+1, end, index, value) self.tree[node] = self.tree[left_child] + self.tree[right_child] def count_pairs(a, b): n = len(a) s = [0] * n s[0] = b[0] for i in range(1, n): s[i] = s[i-1] + b[i] ratios = {} pair_count = 0 seen = set() for i in range(n): for j in range(i+1, n): ratio = a[i] * a[j] if ratio not in ratios: ratios[ratio] = [] ratios[ratio].append((i, j)) tree = SegmentTree(s) for j in range(n): if j > 0 and a[j] != 0: for i, j_ in ratios.get(1/a[j], []): if i < j and (i, j_) not in seen: seen.add((i, j_)) target = a[i] * a[j_] index = tree.query(0, 0, n-1, target) if index <= j-1 and s[index] == target: pair_count += 1 tree.update(0, 0, n-1, j, s[j]) return pair_count ``` 这个解法的时间复杂度是 O(n*log(n)),因为我们需要遍历所有的 i 和 j,每次在 s 数组中进行二分查找,时间复杂度为 log(n)。同时,我们需要对 s 数组进行一次前缀和的计算,时间复杂度为 O(n)。如果使用线段树来维护 s 数组,线段树的构建时间复杂度为 O(n*log(n)),单次更新和查询的时间复杂度也是 O(log(n))。因此,总时间复杂度为 O(n*log(n))。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值