Codeforces 915E Physical Education Lessons(线段树动态开点)

题目链接
题意

初始 [ 1 , n ] [1,n] [1,n] 1 1 1 1 1 1 表示你需要工作,然后 q q q 行操作。
每次操作可以将某个区间 1 1 1 变为 0 0 0,或者 0 0 0 变为 1 1 1,求每次操作后存在多少个 1 1 1

思路

线段树动态开点裸题,离线离散化应该也可以吧。
动态开点相比普通线段树,多维护每个节点的左右儿子,用到某个点才给他开辟空间。
所以区间修改肯定要lazy一下,否则和没开一样。
每次修改开的点大概就logn个

代码
#include <bits/stdc++.h>
using namespace std;

int id;

struct Node
{
    int sum, l, r, lazy;
}t[300005*50];

int build()
{
    ++id;
    t[id].l = t[id].r = t[id].sum = 0;
    t[id].lazy = -1;
    return id;
}

void pushdown(int rt, int l, int r)
{
    if(t[rt].lazy == -1) return;
    int mid = (l+r)>>1;
    if(l != r)
    {
        if(t[rt].l == 0) t[rt].l = build();
        if(t[rt].r == 0) t[rt].r = build();
        t[t[rt].l].lazy = t[rt].lazy;
        t[t[rt].r].lazy = t[rt].lazy;
        t[t[rt].l].sum = (mid-l+1)*t[rt].lazy;
        t[t[rt].r].sum = (r-mid)*t[rt].lazy;
    }
    t[rt].lazy = -1;
}

void updata(int rt, int l, int r, int ql, int qr, int num)
{
    if(ql <= l && r <= qr)
    {
        t[rt].lazy = num;
        t[rt].sum = (r-l+1)*num;
        return;
    }
    pushdown(rt,l,r);
    int mid = (l+r) >> 1;
    if(ql <= mid)
    {
        if(t[rt].l == 0) t[rt].l = build();
        updata(t[rt].l,l,mid,ql,qr,num);
    }
    if(qr > mid)
    {
        if(t[rt].r == 0) t[rt].r = build();
        updata(t[rt].r,mid+1,r,ql,qr,num);
    }
    t[rt].sum = t[t[rt].l].sum+t[t[rt].r].sum;
}

int main()
{
    int n, q;
    scanf("%d%d",&n,&q);
    id = 0;
    build();
    while(q--)
    {
        int x, y, z;
        scanf("%d%d%d",&x,&y,&z);
        if(z == 1) updata(1,1,n,x,y,1);
        else updata(1,1,n,x,y,0);
        printf("%d\n",n-t[1].sum);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值