http://acm.hdu.edu.cn/showproblem.php?pid=1698
这是一个区间染色的问题,对于区间染色问题,通常的方法是在线段树中定义一个cover域,当cover的值为-1的时候,则表示这个线段的覆盖不是有一个颜色染成的,其中包含了多种颜色,而当cover为一个非-1的值时,例如cover==1时表示该线段是有第一种颜色染成的。 对于这题,由于是成段成段的在跟新线段树,我们自然不能简单的递归到根节点再进行处理,这样毫无疑问是要超时的,所以我们只能成段的跟新。
那么,如何做到成段的跟新呢?这里需要运用一种叫着lazy的思想,lazy顾名思义便是懒惰的意思。该思想大概的意思便是:假设要跟新区间[a,b],那么当我们找到区间[a,b]时,便不再往下进行递归,而是在该区间上标记上一个lazy,表示这里有信息需要向下传递。那么当我们需要跟新区间[a,b/2]时,我们便一定会从区间[a,b]经过,经过的过程中,我们发现区间[a,b]有信息需要向下传递,此时便将区间[a,b]的信息传递给其子区间。这样在必要的时候才一层一层的传递,便节约了很多时间。具体见程序吧,很清晰的
View Code
1 #include<iostream>
2 #include<string>
3 using namespace std;
4
5 struct node
6 {
7 int l;
8 int r;
9 int cover;
10 };
11
12 node tree[500000];
13 int n,m;
14
15 void build(int i,int l,int r)
16 {
17 tree[i].l=l;
18 tree[i].r=r;
19 tree[i].cover=1; //初始颜色为1
20 if(l==r)
21 return;
22 int mid=(l+r)/2;
23 build(2*i,l,mid);
24 build(2*i+1,mid+1,r);
25 }
26
27 void updata(int i,int l,int r,int w)
28 {
29 if(tree[i].l>r || tree[i].r<l)
30 return;
31 if(tree[i].l>=l && tree[i].r<=r)
32 {
33 tree[i].cover=w; //cover表示lazy标记,当cover的值不为-1的时候,就说明该区间有信息需要向下传递
34 return;
35 }
36 if(tree[i].cover!=-1) //该区间有信息需要传递
37 {
38 tree[2*i].cover=tree[2*i+1].cover=tree[i].cover; //将其标记传递给子区间
39 tree[i].cover=-1; //同时自身取消标记
40 }
41 updata(2*i,l,r,w);
42 updata(2*i+1,l,r,w);
43 }
44
45 int ans;
46 void find(int i)
47 {
48 if(tree[i].cover!=-1) //单色区间,直接取其值
49 {
50 ans+=(tree[i].r-tree[i].l+1)*tree[i].cover;
51 return;
52 }
53 if(tree[i].l==tree[i].r)
54 return;
55 find(2*i); //非单色区间,则向下递归
56 find(2*i+1);
57 }
58
59 int main()
60 {
61 int cas,i,a,b,c,o=1;
62 freopen("in.txt","r",stdin);
63 scanf("%d",&cas);
64 while(cas--)
65 {
66 scanf("%d%d",&n,&m);
67 build(1,1,n);
68 for(i=0;i<m;i++)
69 {
70 scanf("%d%d%d",&a,&b,&c);
71 updata(1,a,b,c);
72 }
73 ans=0;
74 find(1);
75 printf("Case %d: The total value of the hook is %d.\n",o++,ans);
76 }
77 return 0;
78 }