• P3870 [TJOI2009]开关


    题目描述

    现有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)。
    输出格式:
    每当遇到第二种操作时,输出一行,包含一个整数:此时在查询的区间中打开的灯的数目。

    简述题意

    给出一颗01线段树,对其区间进行xor操作,并查询区间中1的个数

    思路

    最开始想用线段树来记录一个区间是否被xor过,再加上区间长度,后来发现不行,以为在一个区间可能会存在不同xor过的点。然后又想到直接单点查询,才发现复杂度直接O(nm),不可做。
    于是改变思路,用平常思维来写,用sum表示区间和,想了很久怎么更新其值,后来想到,xor一个区间。更新区间只需要用区间长度减去原区间值就好了。lazy的维护用原值xor,同时两次xor就相当于还原。

    代码

    #include<bits/stdc++.h>
    #define lson rt<<1
    #define rson rt<<1|1
    using namespace std;
    const int maxn=1e5+10;
    int lazy[maxn<<2],sum[maxn<<2];
    int res=0;
    int n,m;
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    inline void pushup(int rt)
    {
    	sum[rt]=sum[lson]+sum[rson];
    }
    inline void pushdown(int rt,int m)
    {
    	if(lazy[rt])
    	{
    		sum[lson]=m-(m>>1)-sum[lson];
    		sum[rson]=(m>>1)-sum[rson];
    		lazy[lson]^=1;
    		lazy[rson]^=1;
    		lazy[rt]=0;
    	}
    }
    void update(int L,int R,int l,int r,int rt)
    {
    	if(L<=l&&r<=R)
    	{
    		lazy[rt]^=1;
    		sum[rt]=r-l+1-sum[rt];
    		return;
    	}
    	pushdown(rt,r-l+1);
    	int m=(l+r)>>1;
    	if(L<=m)
    	update(L,R,l,m,lson);
    	if(m<R)
    	update(L,R,m+1,r,rson);
    	pushup(rt);
    }
    inline void query(int L,int R,int l,int r,int rt)
    {
    	if(L<=l&&r<=R)
    	{
    		res+=sum[rt];
    		return;
    	}
    	pushdown(rt,r-l+1);
    	int m=(l+r)>>1;
    	if(L<=m)
    	query(L,R,l,m,lson);
    	if(m<R)
    	query(L,R,m+1,r,rson);
    }
    int main()
    {
    	n=read(),m=read();
    	for(int i=1;i<=m;i++)
    	{
    		int op=read();
    		if(op==0)
    		{
    			int x=read(),y=read();
    			update(x,y,1,n,1);
    		}
    		if(op==1)
    		{
    			int x=read(),y=read();
    			res=0;
    			query(x,y,1,n,1);
    			printf("%d
    ",res);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    集训Day 7 2020.3.7 动态规划(二)
    集训Day 6 2020.3.6 动态规划(一)
    集训Day 5 2020.3.4 杂题选讲(二)
    集训Day 4 2020.3.3 杂题选讲(一)
    集训Day 2 2020.3.1 数论(质数与筛法)
    集训Day 1 2020.2.29 数论复习(gcd)(一)
    [BZOJ4152]The Captain
    知识点清单(全)
    字符串相关知识
    分块相关知识
  • 原文地址:https://www.cnblogs.com/DriverBen/p/10410635.html
Copyright © 2020-2023  润新知