P1276 校门外的树(增强版)

原题链接

考察:线段树 or 模拟

模拟是很简单啦,主要考虑线段树怎么写,本题的线段树比较特殊.

思路:

        基本是参考了大佬的题解.本题的懒标记过于特殊把我写懵了....

        操作 0:砍掉[l,r]区间的树与树苗

        操作 1:种植[l,r]区间的树苗.

        抽象到线段树操作就是 0: [l,r]区间 树数组-1,树苗数组-1.

                                             1:[l,r] 区间 树苗数组+1

        比较难处理的是树或树苗数组在[l,r]区间存在,树苗无法+1.树苗数组在[l,r]区间不存在就无法-1.再者就是计数时,需要计算砍掉的是树还是树苗.

        很好的处理手段是将树与树苗合并统计:ans[0]代表砍掉的树+树苗.ans[1]代表砍掉的树. 第二问的答案是ans[0]-ans[1]

        ans数组比较好维护,只要建立两个线段树即可.

Code:

 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 /*
 6 第一问:存活的树+树苗-树
 7 第二问:被砍的树与树苗-树 
 8 */
 9 const int N = 10010;
10 struct Node{//tag = 1种树,tag = -1砍树 
11     int l,r,sum,tag,cut;//[l,r] sum该区间存活的树,懒标记,被砍的树. 
12 }tr[2][N<<2];//0表示树苗,1表示树 
13 int n,m,op,ans[2];
14 void build(int u,int l,int r,int s)
15 {
16     tr[s][u] = {l,r,0,0,0};
17     if(l==r) {tr[s][u].sum = 1;return;}
18     int mid = l+r>>1;
19     build(u<<1,l,mid,s); build(u<<1|1,mid+1,r,s);
20     tr[s][u].sum = tr[s][u<<1].sum+tr[s][u<<1|1].sum;
21 }
22 void push_down(int u,int s)
23 {
24     if(tr[s][u].tag==1)
25     {
26         tr[s][u<<1].tag = tr[s][u<<1|1].tag = 1;
27         tr[s][u<<1].sum = tr[s][u<<1].r-tr[s][u<<1].l+1;
28         tr[s][u<<1|1].sum = tr[s][u<<1|1].r-tr[s][u<<1|1].l+1;
29     }
30     if(tr[s][u].tag==-1)
31     {
32         tr[s][u<<1].tag = tr[s][u<<1|1].tag = -1;
33         tr[s][u<<1].sum = tr[s][u<<1|1].sum = 0;
34     }
35     tr[s][u].tag = 0;
36 }
37 void plant(int u,int l,int r,int s)
38 {
39     if(tr[s][u].l>=l&&tr[s][u].r<=r)
40     {
41         tr[s][u].tag = 1;
42         tr[s][u].sum = tr[s][u].r-tr[s][u].l+1;
43         return;
44     }
45     push_down(u,s);
46     int mid = tr[s][u].l+tr[s][u].r>>1;
47     if(l<=mid) plant(u<<1,l,r,s);
48     if(mid<r) plant(u<<1|1,l,r,s);
49     tr[s][u].sum = tr[s][u<<1].sum+tr[s][u<<1|1].sum;
50 }
51 void Cut(int u,int l,int r,int s)
52 {//被砍的树与树苗 
53     if(tr[s][u].l>=l&&tr[s][u].r<=r)
54     {
55         tr[s][u].tag = -1;
56     //    tr[s][u].cut += tr[s][u].sum; 
57         ans[s]+=tr[s][u].sum; 
58         tr[s][u].sum = 0;
59         return;
60     }
61     push_down(u,s);
62     int mid = tr[s][u].l+tr[s][u].r>>1;
63     if(l<=mid) Cut(u<<1,l,r,s);
64     if(mid<r) Cut(u<<1|1,l,r,s);
65     tr[s][u].sum = tr[s][u<<1].sum+tr[s][u<<1|1].sum;
66 //    tr[s][u].cut += tr[s][u<<1].cut+tr[s][u<<1|1].cut;
67 //没有新增砍树会被重复记录 
68 }
69 int main() 
70 {
71     scanf("%d%d",&n,&m);
72     n++;
73     build(1,1,n,0); build(1,1,n,1);
74     while(m--)
75     {
76         int op,l,r;
77         scanf("%d%d%d",&op,&l,&r);
78         l++,r++;
79         if(!op) Cut(1,l,r,0),Cut(1,l,r,1);
80         else plant(1,l,r,0);
81     }
82     printf("%d\n",tr[0][1].sum-tr[1][1].sum);
83 //    printf("%d\n",tr[0][1].cut-tr[1][1].cut); 
84     printf("%d\n",ans[0]-ans[1]);
85     return 0;
86 }

 

        

posted @ 2021-05-20 00:36  acmloser  阅读(249)  评论(0编辑  收藏  举报