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 }