HDU 6183 Color it(动态开点线段树)

题目原网址:http://acm.hdu.edu.cn/showproblem.php?pid=6183

题目中文翻译:

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)
Total Submission(s): 1677    Accepted Submission(s): 500

Problem Description

你喜欢画画吗? Little D不喜欢画画,特别是杂乱的彩色画。 现在Little B正在画画。 为了防止他画出凌乱的画作,Little D要求你写一个程序来维持以下的操作。 这些操作的具体格式如下。

0:清除所有点。

1 x y c:在点(x,y)处添加颜色为c的点, 注意这里一个点可以有很多种颜色,是不会被覆盖的。

2 x y1 y2:计算方形(1,y1)和(x,y2)中有多少种不同的颜色。 也就是说,如果存在着色点c(a,b),即1≤a≤x且y1≤b≤y2,则应计算颜色c。

3:退出。

Input

输入包含许多行。

每行包含一个操作。 它可以是‘0‘,‘1 x y c‘(1≤x,y≤106,0≤c≤50),‘2 x y1 y2‘(1≤x,y1,y2≤106)或‘3‘。

x,y,c,y1,y2都是整数。

假设最后一个操作是3,它只出现一次。

操作1和操作2的连续操作最多为150000次。

最多有10个操作0。

Output

对于每个操作2,输出整数表示答案。

Sample Input

0

1 1000000 1000000
50

1 1000000 999999 0

1 1000000 999999 0

1 1000000 1000000
49

2 1000000 1000000
1000000

2 1000000 1
1000000

0

1 1 1 1

2 1 1 2

1 1 2 2

2 1 1 2

1 2 2 2

2 1 1 2

1 2 1 3

2 2 1 2

2 10 1 2

2 10 2 2

0

1 1 1 1

2 1 1 1

1 1 2 1

2 1 1 2

1 2 2 1

2 1 1 2

1 2 1 1

2 2 1 2

2 10 1 2

2 10 2 2

3

Sample Output

2

3

1

2

2

3

3

1

1

1

1

1

1

1

解题思路:

这道题有50种颜色需要我们处理,比较麻烦,我们不妨先考虑只有一种颜色怎么解决.

因为这道题要我们求的方形是十分特殊的,为(1,y1)和(x,y2),那就说明这个方形是紧贴y轴分布的:

然后我们就会清楚地发现,只要这个颜色的点纵坐标在y1和y2之间,并且横坐标小于x即可.

然后我们在y轴上维护一个线段树,记录x最小值即可(因为只要小于x即可,所以我们只需要记录最小的那一个).



回归正题,我们刚才成功的处理了一种颜色的情况,现在再来考虑50种颜色的情况.

最容易想到的就是维护50个线段树,对于这道题而言时间限制完全可以,但是对于空间则不满足要求,所以我们引用一个优化的方法

----动态开点线段树,它的工作原理就是每当我要用到一个点来维护一个区间时,现开一个空间给它,用不到的点我就不去开辟也不去访,只需提前开两倍的空间即可,大大降低空间浪费.

AC代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4
 5 using namespace std;
 6
 7 int noip,noi,root[51],flag;
 8 struct kkk {
 9     int ls,rs,value;//因为用一棵线段树维护50种颜色,所以不能用2i和2i+1表示左右儿子了
10     kkk() {ls = rs = value = 0;}
11 }e[3000001];
12
13 void update(int &c,int l,int r,int v,int h) {
14     if(!c) {//如果当前点没被开辟,现开辟一个
15         c = ++noi;
16         e[c].value = v;
17     }
18     e[c].value = min(e[c].value,v);//因为要求最小值
19     if(l == r) return ;//如果是叶子节点,就返回
20     int mid = (l + r) >> 1;
21     if(h <= mid) update(e[c].ls,l,mid,v,h);//开左儿子
22     else update(e[c].rs,mid + 1,r,v,h);//开右儿子
23 }
24
25 void yin_wei_bu_hui_zhe_ge_de_ying_wen_suo_yi_yong_zhong_wen_jiao_cha_xun(int c,int x,int l,int r,int ll,int rr) {
26     if(flag || !c) return ;//如果已经有一个点在方形内或这个点没被开辟,就返回
27     if(ll <= l && rr >= r) {//如果纵坐标满足要求
28         if(e[c].value <= x) flag = 1;//横坐标满足要求,说明在方形内,标记一下
29         return ;
30     }
31     int mid = (l + r) >> 1;
32     if(ll <= mid) yin_wei_bu_hui_zhe_ge_de_ying_wen_suo_yi_yong_zhong_wen_jiao_cha_xun(e[c].ls,x,l,mid,ll,rr);
33     if(rr > mid) yin_wei_bu_hui_zhe_ge_de_ying_wen_suo_yi_yong_zhong_wen_jiao_cha_xun(e[c].rs,x,mid + 1,r,ll,rr);
34 }
35
36 int main() {
37     while(scanf("%d",&noip)) {
38         if(noip == 3) break;
39         if(noip == 0) {
40             for(int i = 1;i <= noi; i++) e[i].ls = e[i].rs = e[i].value = 0;
41             for(int i = 0;i <= 50; i++) memset(root,0,sizeof(root));
42             noi = 0;
43         }
44         if(noip == 1) {
45             int x,y,c;
46             scanf("%d%d%d",&x,&y,&c);
47             update(root[c],1,1000000,x,y);
48         }
49         if(noip == 2) {
50             int x,x1,y1;
51             scanf("%d%d%d",&x,&x1,&y1);
52             int ans = 0;
53             for(int i = 0;i <= 50; i++) {
54                 flag = 0;
55                 yin_wei_bu_hui_zhe_ge_de_ying_wen_suo_yi_yong_zhong_wen_jiao_cha_xun(root[i],x,1,1000000,x1,y1);
56                 if(flag) ans++;
57             }
58             printf("%d\n",ans);
59         }
60     }
61     return 0;
62 }

原文地址:https://www.cnblogs.com/lipeiyi520/p/10961683.html

时间: 2024-12-29 23:13:06

HDU 6183 Color it(动态开点线段树)的相关文章

HDU6183 Color it 动态开点线段树

网址:https://vjudge.net/problem/HDU-6183 题意: 给出以下操作:$“0”$代表清空所有颜色,$"1$ $x$ $y$ $c$$"$代表在坐标$(x,y)$涂上第$c$种颜色,$"2$ $x$ $y_1$ $y_2$$"$代表统计$x$轴上$[1,x]$和y轴上$[y_1,y_2]$的颜色数,一个点可以有多种颜色,$“3”$代表结束.数据保证$n,m \leq 1e6,0 \geq c \leq 50,y_1 \leq y_2$.

HDU 6681 Rikka with Cake(扫描线、动态开点线段树)

http://acm.hdu.edu.cn/showproblem.php?pid=6681 题意 在矩形区域内有k条射线,问这些射线将矩形分成了多少区域 题解 容易发现答案为所有射线交点个数. 按y从排序扫描矩形区域,动态开点线段树维护区间内竖线的个数,由于n,m范围较大,需要离散化处理,但这样比较麻烦且此题空间足够所以建议用动态开点. 1 #define bug(x) cout<<#x<<" is "<<x<<endl 2 #defi

【BZOJ-4636】蒟蒻的数列 动态开点线段树 ||(离散化) + 标记永久化

4636: 蒟蒻的数列 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 247  Solved: 113[Submit][Status][Discuss] Description 蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列 题目描述 DCrusher有一个数列,初始值均为0,他进行N次操作,每次将数列[a,b)这个区间中所有比k小的数改为k,他想知 道N次操作后数列中所有元素的和.他还要玩其他游戏,所以这个问题留给你解决. Input 第一

Codeforces 803G Periodic RMQ Problem ST表+动态开节点线段树

思路: (我也不知道这是不是正解) ST表预处理出来原数列的两点之间的min 再搞一个动态开节点线段树 节点记录ans 和标记 lazy=-1 当前节点的ans可用  lazy=0 没被覆盖过 else 区间覆盖 push_up的时候要注意好多细节,, 数组尽量往大开 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const in

【bzoj3939】[Usaco2015 Feb]Cow Hopscotch 动态开点线段树优化dp

题目描述 Just like humans enjoy playing the game of Hopscotch, Farmer John's cows have invented a variant of the game for themselves to play. Being played by clumsy animals weighing nearly a ton, Cow Hopscotch almost always ends in disaster, but this has

【bzoj4999】This Problem Is Too Simple! 树链剖分+动态开点线段树

题目描述 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点. 输入 第一行有两个整数N,Q(1 ≤N≤ 100,000:1 ≤Q≤ 200,000),分别表示节点个数和操作个数. 下面一行N个整数,表示初始时每个节点的初始值. 接下来N-1行,每行两个整数x,y,表示x节点与y节点之间有边直接相连(描述一颗树).

CF1045G AI robots(动态开点线段树)

题意 火星上有$N$个机器人排成一行,第$i$个机器人的位置为$x_{i}$,视野为$r_{i}$,智商为$q_{i}$.我们认为第$i$个机器人可以看到的位置是$[x_{i}-r_{i},x_{i}+r_{i}]$.如果一对机器人相互可以看到,且它们的智商$q_{i}$的差距不大于$K$,那么它们会开始聊天. 为了防止它们吵起来,请计算有多少对机器人可能会聊天. 题解 先膜一下大佬->这里 我们先按视野降序排序,这样一个一个考虑,如果后面的能看到前面,那前面的也肯定能看到后面 这样,就是对于每

CF915E Physical Education Lessons|动态开点线段树

动态开点线段树 题目暗示了区间修改,所以我们自然想到了用线段树来维护非工作日的天数. 然而我们再看一下数据范围,天数n的范围是\(1 \le n \le 10^9\),像普通线段树一样预处理显然会爆空间. 天无绝人之路,我们看一下修改个数,$1\le q \le 3 \cdot 10^5 $, 比天数少很多,这也意味着,我们预先处理好的线段树有些节点并没有用 能否优化呢?答案是肯定的,这就是动态开点线段树,顾名思义,我们只要到用某个节点的时候,才分配一个点给它,这样使得我们使用的空间大大减少.其

动态开点线段树

用途 需要建立多棵独立的线段树 线段树维护的值域较大(1e9),但是操作次数较少(1e5) 特征 类似主席树的原理,动态分配每个树节点的位置(lson[],rson[]),每次只更新一条链,但是主席树是建立一颗新的树,动态开点线段树是在一棵树上不断添加节点(还是一棵树) 类似线段树的原理,push_down区间修改,push_up区间查询 例题 1.维护值域较大,线段树区间修改 cf915e https://codeforces.com/contest/915/problem/E 题意: q(3