zoukankan      html  css  js  c++  java
  • 线段树2

    先来看一下这道模板题:

    https://www.luogu.org/problem/P2846

    题目大意:

    开始所有灯都是暗的,

    改变:每次操作可以改变两盏灯之间所有灯的状态(亮变暗,暗变亮),

    查询:每次查询两盏灯之间亮的灯的个

    这道题与线段树1中讲的那道题大部分都是一样的,只有一点,

    那就是如何在线段树上区间修改

    很明显,如果在线段树上执行n次单点修改,时间复杂度会达到O(n^2logn)

    比朴素算法更劣,所以要找到更好的解决办法

    我们可以在这棵树上的某些节点上标记lazy

    表示这个节点对应的区间都要修改

    但该节点的所有后代节点的num值都不修改

    只修改当前节点的num值

    但由于打上了lazy下次还能找到该节点

    如果查询时遇到lazy标记的节点

    就将标记下沉(取消该节点的lazy,并lazy标记上它的两个子节点,再修改它两个子节点的num值)

    这样就能用O(logn)完美解决区间修改问题

    再具体说一下这道题,这道题需要用上状态压缩

    比如将

    开、开、关、开、关、关

    用二进制数110100来表示

    变为十进制就是52,这样就可以用52表示 开、开、关、开、关、关这个状态

    这样每个节点num存的就是它表示的区间中的状态对应的十进制数

    最后,给大家看一下代码:

    #include<bits/stdc++.h>
    using namespace std;
    int num[100000*4];
    bool lazy[100000*4];
    void build(int l,int r,int root)
    {
    	if(l==r)
    	{
    		num[root]=0;
    		return;
    	}
    	int mid=(l+r)/2;
    	build(l,mid,root*2);
    	build(mid+1,r,root*2+1);
    	num[root]=num[root*2]+num[root*2+1];
    }
    void change(int p,int q,int l,int r,int root)
    {
    	//printf("%d %d %d %d %d
    ",p,q,l,r,root);
    	if(p==l && q==r)
    	{
    		lazy[root]=1-lazy[root];
    		num[root]=r-l+1-num[root];
    		//cout<<num[root]<<" "<<root<<endl;
    		return;
    	}
    	int mid=(l+r)/2;
    	if(lazy[root])
    	{
    		lazy[root*2]=1-lazy[root*2];
    		lazy[root*2+1]=1-lazy[root*2+1];
    		lazy[root]=0;
    		num[root*2]=mid-l+1-num[root*2];
    		num[root*2+1]=r-mid-num[root*2+1];
    	}
    	if(q<=mid) change(p,q,l,mid,root*2);
    	else if(p>=mid+1) change(p,q,mid+1,r,root*2+1);
    	else change(p,mid,l,mid,root*2),change(mid+1,q,mid+1,r,root*2+1);
    	num[root]=num[root*2]+num[root*2+1];
    }
    int search(int p,int q,int l,int r,int root)
    {
    	if(p==l && q==r)
    	{
    		return num[root];
    	}
    	int mid=(l+r)/2;
    	if(lazy[root])
    	{
    		lazy[root*2]=1-lazy[root*2];
    		lazy[root*2+1]=1-lazy[root*2+1];
    		lazy[root]=0;
    		num[root*2]=mid-l+1-num[root*2];
    		num[root*2+1]=r-mid-num[root*2+1];
    	}
    	if(q<=mid) return search(p,q,l,mid,root*2);
    	else if(p>=mid+1) return search(p,q,mid+1,r,root*2+1);
    	else return search(p,mid,l,mid,root*2)+search(mid+1,q,mid+1,r,root*2+1);
    }
    int main()
    {
    	int n,w;
    	scanf("%d%d",&n,&w);
    	for(int i=1;i<=w;i++)
    	{
    		int t;
    		int x,y;
    		scanf("%d%d%d",&t,&x,&y);
    		if(t==0) change(x,y,1,n,1);
    		else if(t==1) printf("%d
    ",search(x,y,1,n,1));
    	}
    	return 0;
    }
    

    最后,再给大家推荐几到简单的养身模板

    https://www.luogu.org/problem/P1937

    https://www.luogu.org/problem/P1438

    https://www.luogu.org/problem/U84988

    https://www.luogu.org/problem/P1533

    https://www.luogu.org/problem/P2574

  • 相关阅读:
    JQ实时监听input的value值
    css 超过一行省略号
    后端传过来一个JS代码,前端拿到之后执行
    Ant design vue table 单击行选中 勾选checkbox
    原生js实现addClass,removeClass,hasClass方法
    JS动态添加JavaScript语句
    js数字卷轴滚动
    spark在eclipse下V2-02逐个运行spark-examples
    spark在eclipse下V2-搭建Demo代码阅读环境
    试下Inceptor事务表和HDFS目录的关系。
  • 原文地址:https://www.cnblogs.com/chen-1/p/11442635.html
Copyright © 2011-2022 走看看