Codeforce 915E(线段树动态开点)

╰+攻爆jí腚メ 2021-11-01 07:10 483阅读 0赞

日常安利:https://blog.csdn.net/stay_accept/article/details/79210918
知识共享许可协议
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
This year Alex has finished school, and now he is a first-year student of Berland State University. For him it was a total surprise that even though he studies programming, he still has to attend physical education lessons. The end of the term is very soon, but, unfortunately, Alex still hasn’t attended a single lesson!
Since Alex doesn’t want to get expelled, he wants to know the number of working days left until the end of the term, so he can attend physical education lessons during these days. But in BSU calculating the number of working days is a complicated matter:
There are n days left before the end of the term (numbered from 1 to n), and initially all of them are working days. Then the university staff sequentially publishes q orders, one after another. Each order is characterised by three numbers l, r and k:
If k = 1, then all days from l to r (inclusive) become non-working days. If some of these days are made working days by some previous order, then these days still become non-working days;
If k = 2, then all days from l to r (inclusive) become working days. If some of these days are made non-working days by some previous order, then these days still become working days.
Help Alex to determine the number of working days left after each order!
Input
The first line contains one integer n, and the second line — one integer q (1 ≤ n ≤ 109, 1 ≤ q ≤ 3·105) — the number of days left before the end of the term, and the number of orders, respectively.
Then q lines follow, i-th line containing three integers li, ri and ki representing i-th order (1 ≤ li ≤ ri ≤ n, 1 ≤ ki ≤ 2).
Output
Print q integers. i-th of them must be equal to the number of working days left until the end of the term after the first i orders are published.
Example
Input
4
6
1 2 1
3 4 1
2 3 2
1 3 2
2 4 1
1 4 2
Output
2
0
2
3
1
4
分析:
这个题的n范围虽然很大,但是q不是很大。 所以可以用离散化在建线段树的方法。在结点里面维护一个区间和即可。

不过,正好在学动态开点。所以这个题就用了一下动态开点+laze标记。
laze标记,是指表示该结点曾经被修改,但是其子结点未被更新。
同时动态开点无非就是把2id 和2id+1作为子孩子,现在改用变量来记录其子结点。

  1. #include"stdio.h"
  2. #include"string.h"
  3. #include"algorithm"
  4. using namespace std;
  5. int n,q;
  6. int laze[5 * 3000100],sum[5 * 3000100],lson[5 * 3000100],rson[5 * 3000100];
  7. int top;
  8. void push_down(int id,int l,int r)
  9. {
  10. if(laze[id] == -1)
  11. return;
  12. if(lson[id] == 0)
  13. lson[id] = ++ top;
  14. if(rson[id] == 0)
  15. rson[id] = ++ top;
  16. int mid = (l + r) >> 1;
  17. sum[lson[id]] = (mid - l + 1) * laze[id];
  18. laze[lson[id]] = laze[id];
  19. sum[rson[id]] = (r - (mid + 1) + 1) * laze[id];
  20. laze[rson[id]] = laze[id];
  21. laze[id] = -1;
  22. }
  23. void Update(int id,int L,int R,int l,int r,int val)
  24. {
  25. // printf("id = %d L = %d R = %d l = %d r = %d val = %d\n",id,L,R,l,r,val);
  26. if(l <= L && r >= R)
  27. {
  28. laze[id] = val;
  29. sum[id] = (R - L + 1) * val;
  30. return ;
  31. }
  32. push_down(id,L,R);
  33. int mid = (L + R) >> 1;
  34. if(l <= mid)
  35. {
  36. if(lson[id] == 0)//这里注意一下,不能把Update也写在if里面
  37. {
  38. lson[id] = ++ top;
  39. }
  40. Update(lson[id],L,mid,l,r,val);
  41. }
  42. if(r > mid)
  43. {
  44. if(rson[id] == 0)
  45. {
  46. rson[id] = ++ top;
  47. }
  48. Update(rson[id],mid + 1,R,l,r,val);
  49. }
  50. sum[id] = sum[lson[id]] + sum[rson[id]];
  51. }
  52. int main()
  53. {
  54. scanf("%d",&n);
  55. scanf("%d",&q);
  56. for(int i = 1; i <= 40 * q; i ++)
  57. laze[i] = -1;
  58. for(int i = 1; i <= q; i ++)
  59. {
  60. int l,r,op;
  61. scanf("%d%d%d",&l,&r,&op);
  62. if(op == 2)
  63. op = 0;
  64. Update(0,1,n,l,r,op);
  65. printf("%d\n",n - sum[0]);
  66. }
  67. }

发表评论

表情:
评论列表 (有 0 条评论,483人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Codeforces 750E 线段DP

    题意:给你一个字符串,有两种操作:1:把某个位置的字符改变。2:询问l到r的子串最少需要删除多少个字符,使得这个子串含有2017子序列,并且没有2016子序列? 思路:线段树