• 题解 P3870 【[TJOI2009]开关】


    这个题我愣是交了好几遍没有过......
    后来@_皎月半洒花dalao告诉我说要^儿子节点的tag,然后就明白了......

    行吧,先上题面:

    题目描述

    现有N(2 ≤ N ≤ 100000)盏灯排成一排,从左到右依次编号为:1,2,......,N。然后依次执行M(1 ≤ M ≤ 100000)项操作,操作分为两种:第一种操作指定一个区间[a, b],然后改变编号在这个区间内的灯的状态(把开着的灯关上,关着的灯打开),第二种操作是指定一个区间[a, b],要求你输出这个区间内有多少盏灯是打开的。灯在初始时都是关着的。

    输入输出格式

    输入格式:

    第一行有两个整数N和M,分别表示灯的数目和操作的数目。接下来有M行,每行有三个整数,依次为:c, a, b。其中c表示操作的种类,当c的值为0时,表示是第一种操作。当c的值为1时表示是第二种操作。a和b则分别表示了操作区间的左右边界(1 ≤ a ≤ b ≤ N)。

    输出格式:

    每当遇到第二种操作时,输出一行,包含一个整数:此时在查询的区间中打开的灯的数目。

    这个题比较有好处的一点是有很多题都和这个题基本一样。
    然后我们看到这个题让我们统计一个线段内的某一种和和修改区间:

    线段树啊!

    然后我就把校门外的树的代码扒过来了......
    评测记录
    后果:听取WA声一片。

    为啥呢?

    因为儿子节点有可能比父亲节点提前改过了。
    所以我们只能取反,把原先的状态反过来。
    然后就成了提交记录

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    const int maxn=100001;
    struct tree{
    	int l,r,flash,dark;
    	bool tag;
    }segment[maxn<<2];
    int n,m;
    
    inline void update(int rt);
    inline void pushdown(int rt);
    inline void build_tree(int rt,int l,int r);
    inline int query(int rt,int l,int r);
    inline void modify(int rt,int l,int r);
    
    int main()
    {
    	cin>>n>>m;
    	build_tree(1,1,n);
    	while (m--)
    	{
    		char flag;
    		int l,r;
    		cin>>flag>>l>>r;
    		if (flag=='0')modify(1,l,r);
    		else cout<<query(1,l,r)<<'
    ';
    	}
    	return 0;
    }
    
    inline void update(int rt)
    {
    	int lson=rt<<1,rson=lson+1;
    	segment[rt].flash=segment[lson].flash+segment[rson].flash;
    	segment[rt].dark=segment[lson].dark+segment[rson].dark;
    }
    inline void pushdown(int rt)
    {
    	int lson=rt<<1,rson=lson+1;
    	segment[lson].tag^=1;
    	segment[rson].tag^=1;
    	swap(segment[lson].dark,segment[lson].flash);
    	swap(segment[rson].dark,segment[rson].flash);
    	segment[rt].tag^=1;
    }
    inline void build_tree(int rt,int l,int r)
    {
    	segment[rt].l=l,segment[rt].r=r;
    	if (l==r)
    	{
    		segment[rt].flash=0;
    		segment[rt].dark=1;
    		segment[rt].tag=false;
    		return;
    	}
    	int mid=(r+l)>>1,lson=rt<<1,rson=lson+1;
    	build_tree(lson,l,mid);
    	build_tree(rson,mid+1,r);
    	update(rt);
    }
    inline void modify(int rt,int l,int r)
    {
    	if (segment[rt].l<=l&&segment[rt].r>=r)
    	{
    		if (segment[rt].l==l&&segment[rt].r==r)
    		{
    			segment[rt].tag^=1;
    			swap(segment[rt].flash,segment[rt].dark);
    			return;
    		}
    		if (segment[rt].tag)pushdown(rt);
    		int mid=(segment[rt].l+segment[rt].r)>>1,lson=rt<<1,rson=lson+1;
    		if (r<=mid)modify(lson,l,r);
    		else if (l>mid)modify(rson,l,r);
    		else
    		{
    			modify(lson,l,mid);
    			modify(rson,mid+1,r);
    		}
    		update(rt);
    	}
    	return ;
    }
    inline int query(int rt,int l,int r)
    {
    	if (segment[rt].l<=l&&segment[rt].r>=r)
    	{
    		if (segment[rt].l==l&&segment[rt].r==r)
    		{
    			return segment[rt].flash;
    		}
    		if (segment[rt].tag)pushdown(rt);
    		int mid=(segment[rt].l+segment[rt].r)>>1,lson=rt<<1,rson=lson+1;
    		if (r<=mid)return query(lson,l,r);
    		else if (l>=mid+1)return query(rson,l,r);
    		else return query(lson,l,mid)+query(rson,mid+1,r);
    	}
    	return 0;
    }
    

    行吧......

  • 相关阅读:
    算术入门之加减乘除
    scanf的返回值
    Flutter 开发环境配置
    DbContextOptionsBuilder
    MarkDown 的简单用法
    C# 多线程安全集合类
    .NET Core 中使用 MemoryCache 缓存
    JWT
    什么是跨域?跨域解决方法
    .Net Core 中配置的高级用法
  • 原文地址:https://www.cnblogs.com/jelly123/p/10390559.html
Copyright © 2020-2023  润新知