线段树

1.前言

刚刚接触编程不久,学习到了线段树,就做一个自己的总结。可能很烂。。。

1.1什么是树?

1.1.1树的定义

树(Tree)是n(n>=0)个结点的有限集。n=0时称为空树。在任意一颗非空树中:
1.有且仅有一个特定的称为根(root)的结点;
2.当n>1时,其余结点可分为m(m>0)个互补交互的有限集T1、T2…Tm,其中每一个集合本身又是一棵树,并称为根的子树(SubTree)。这是一棵树

1.1.2树的特点

  • n>0时,根节点是唯一的,不可能存在多个根节点。数据结构中的树只有一个根节点。
  • m>0时,子树的个数没有限制,但他们一定是互不相交的。

1.1.3结点的分类

  1. 结点:树的结点包含一个数据元素和若干指向其子树的分支
  2. 结点的度(Degree):结点拥有的子树。
  3. 叶子结点(Leaf)/终端结点:度为0的结点。
  4. 分支结点/非终端结点:度不为0的结点。
  5. 内部结点:除根结点以外,分支结点也称为内部结点。
  6. 树的度:树内各结点的度的最大值。
    在这里插入图片描述

1.2线段树算法简介

线段树,顾名思义就是由一个一个线段组成的一棵树,每个结点都是一个线段(叶子结点是单元结点),那么每个结点应该包括:
7. 区间左右端点。
8. 区间要维护的信息(情况不同,操作不同)。
即每个结点还是一个结构体。区间上可以进行区间查询,修改,求和等操作。线段树还是一棵二叉搜索树。其主要作用是高效解决连续区间的动态查询问题。
示意图:
在这里插入图片描述
其中结点的数字代表第几个结点,红色数字代表这个点表示的区间范围。
有结构图可知:

  1. 每个结点的左儿子区间的范围为[l,mid],右儿子为[mid+1,r]
  2. 对于结点k,左儿子结点为2k,右儿子为2k+1。

2.线段数的构造及操作实现

2.1线段树的建立

首先建立一个结构体,为了方便使用了结构体封装函数。

struct SegmentTree
{
	#define lson (node << 1)   //lson代表左儿子结点
	#define rson (node << 1 | 1)  //rson代表右儿子结点
	static const int N=1e6+10;
	ll sum[N << 2];   //由于线段树的特点所以数组长度开为4倍
	void pushup(int node)
	{
		sum[node]=sum[lson]+sum[rson];
	}
	void build(int node, int l, int r)
	{
		if(l == r){
			sum[node]=a[l];//注意一定是左区间
			return ;
		}
		int mid=l+r>>1;
		build(lson,l,mid);
		build(rson,mid+1,r);
		pushup(node);//从叶子结点开始不断地求和到根节点
	}
}tree;

2.2单点修改

还是在同一个结构体内写。

void change(int node, int l, int r, int idx,int x)
	{
		if(l==r){
			sum[node]+=x;
			return ;
		}
		int mid=l+r>>1;
		//下面两步就是在二分查询。
		if(idx<=mid) change(lson,l,mid,idx,x);
		else change(rson,mid+1,r,idx,x);
		pushup(node);//单点修改结束后,需要更新所在区间。
	}
	

2.3区间查询

ll query(int node, int l, int r, int L, int R)
	{
		if(l==L&&r==R)
		{
			return sum[node];
		}
		spread(node,l,r);
		int mid=l+r>>1;
		if(R<=mid) return query(lson, l, mid, L, R);
		else if(L>mid) return query(rson, mid+1,r,L,R);
		else{
			ll ans=0;
			ans+=query(lson,l,mid,L,mid);
			ans+=query(rson,mid+1,r,mid+1,R);
			return ans;
		}
	}

2.4区间修改

void spread(int node, int l, int r)
	{
		if(lazylag[node])
		{
			int mid=l+r>>1;
			sum[lson]+=1ll*lazylag[node]*(mid-l+1);
			sum[rson]+=1ll*lazylag[node]*(r-mid);
			lazylag[lson]+=lazylag[node];
			lazylag[rson]+=lazylag[node];
			lazylag[node]=0;
		}
	}
void intervalchange(int node, int l, int r, int L,int R,int x)
	{
		if(l==L&&r==R)
		{
			lazylag[node]+=x;
			sum[node]+=1ll*x*(r-l+1);
			return ;
		}
		spread(node,l,r);
		int mid=l+r>>1;
		if(R<=mid) intervalchange(lson,l,mid,L,R,x);
		else if(L>mid) intervalchange(rson,mid+1,r,L,R,x);
		else{
			intervalchange(lson,l,mid,L,mid,x);
			intervalchange(rson,mid+1,r,mid+1,R,x);
		}
		pushup(node);
	}

2.5单点查询

ll idquery(int node,int l,int r, int idx)
	{
		if(l==r)
		{
			return sum[node];
		}
		int mid=l+r>>1;
		spread(node,l,r);
		if(mid>=idx)
		return idquery(lson,l,mid,idx);
		else
		return idquery(rson,mid+1,r,idx);
	}

3例题

3.1【模板】单点修改,区间查询

单点修改,区间查询的板子题

#include <bits/stdc++.h>
#define ll long long
using namespace std;

ll a[1000000+1000];
struct SegmentTree
{
	#define lson (node << 1)
	#define rson (node << 1 | 1)
	static const int N=1e6+10;
	ll sum[N << 2];
	void pushup(int node)
	{
		sum[node]=sum[lson]+sum[rson];
	}
	void build(int node, int l, int r)
	{
		if(l == r){
			sum[node]=a[l];
			return ;
		}
		int mid=l+r>>1;
		build(lson,l,mid);
		build(rson,mid+1,r);
		pushup(node);
	}
	void change(int node, int l, int r, int idx,int x)
	{
		if(l==r){
			sum[node]+=x;
			return ;
		}
		int mid=l+r>>1;
		if(idx<=mid) change(lson,l,mid,idx,x);
		else change(rson,mid+1,r,idx,x);
		pushup(node);
	}
	ll query(int node, int l, int r, int L, int R)
	{
		if(l==L&&r==R)
		{
			return sum[node];
		}
		int mid=l+r>>1;
		if(R<=mid) return query(lson, l, mid, L, R);
		else if(L>mid) return query(rson, mid+1,r,L,R);
		else{
			ll ans=0;
			ans+=query(lson,l,mid,L,mid);
			ans+=query(rson,mid+1,r,mid+1,R);
			return ans;
		}
	}
}tree;
int main()
{
	int n,q;
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	tree.build(1,1,n);
	while(q--)
	{
		int s,l1,r1;
		scanf("%d%d%d",&s,&l1,&r1);
		if(s==1)
		{
			tree.change(1,1,n,l1,r1);
		}
		if(s==2)
		{
			ll sem=tree.query(1,1,n,l1,r1);
			printf("%lld\n",sem);
		}
	}
	return 0;
}

3.2区间修改,单点查询

同样的板子题

#include <bits/stdc++.h>
#define ll long long

using namespace std;

int a[4000000+100];
struct SegmentTree
{
	#define lson (node << 1)
	#define rson (node << 1 | 1)
	static const int N=1e6+10;
	ll sum[N << 2];
	ll lazylag[N<<2];
	void pushup(int node)
	{
		sum[node]=sum[lson]+sum[rson];
	}
	void spread(int node, int l, int r)
	{
		if(lazylag[node])
		{
			int mid=l+r>>1;
			sum[lson]+=1ll*lazylag[node]*(mid-l+1);
			sum[rson]+=1ll*lazylag[node]*(r-mid);
			lazylag[lson]+=lazylag[node];
			lazylag[rson]+=lazylag[node];
			lazylag[node]=0;
		}
	}
	void build(int node, int l, int r)
	{
	
		lazylag[node]=0;
		if(l == r){
			sum[node]=a[l];
			return ;
		}
		int mid=l+r>>1;
		build(lson,l,mid);
		build(rson,mid+1,r);
		pushup(node);
	}
//	void change(int node, int l, int r, int idx,int x)
//	{
//		if(l==r){
//			sum[node]+=x;
//			return ;
//		}
//		spread(node,l,r);
//		int mid=l+r>>1;
//		if(idx<=mid) change(lson,l,mid,idx,x);
//		else change(rson,mid+1,r,idx,x);
//		pushup(node);
//	}
	void intervalchange(int node, int l, int r, int L,int R,int x)
	{
		if(l==L&&r==R)
		{
			lazylag[node]+=x;
			sum[node]+=1ll*x*(r-l+1);
			return ;
		}
		spread(node,l,r);
		int mid=l+r>>1;
		if(R<=mid) intervalchange(lson,l,mid,L,R,x);
		else if(L>mid) intervalchange(rson,mid+1,r,L,R,x);
		else{
			intervalchange(lson,l,mid,L,mid,x);
			intervalchange(rson,mid+1,r,mid+1,R,x);
		}
		pushup(node);
	}
	ll idquery(int node,int l,int r, int idx)
	{
		if(l==r)
		{
			return sum[node];
		}
		int mid=l+r>>1;
		spread(node,l,r);
		if(mid>=idx)
		return idquery(lson,l,mid,idx);
		else
		return idquery(rson,mid+1,r,idx);
	}
//	ll query(int node, int l, int r, int L, int R)
//	{
//		if(l==L&&r==R)
//		{
//			return sum[node];
//		}
//		int mid=l+r>>1;
//		if(R<=mid) return query(lson, l, mid, L, R);
//		else if(L>mid) return query(rson, mid+1,r,L,R);
//		else{
//			ll ans=0;
//			ans+=query(lson,l,mid,L,mid);
//			ans+=query(rson,mid+1,r,mid+1,R);
//			return ans;
//		}
//	}
}tree;
int main()
{
	int n,q;
	cin>>n>>q;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	tree.build(1,1,n);
	while(q--)
	{
		int s;
		scanf("%d",&s);
		if(s==1)
		{
			int l,r,x;
			scanf("%d%d%d",&l,&r,&x);
			tree.intervalchange(1,1,n,l,r,x);
		}
		if(s==2)
		{
			int i;
			scanf("%d",&i);
			printf("%lld\n",tree.idquery(1,1,n,i));
		}
	}
	return 0;
}

3.3区间修改,区间查询

板子题

#include <bits/stdc++.h>
#define ll long long

using namespace std;

int a[4000000+100];
struct SegmentTree
{
	#define lson (node << 1)
	#define rson (node << 1 | 1)
	static const int N=1e6+10;
	ll sum[N << 2];
	ll lazylag[N<<2];
	void pushup(int node)
	{
		sum[node]=sum[lson]+sum[rson];
	}
	void spread(int node, int l, int r)
	{
		if(lazylag[node])
		{
			int mid=l+r>>1;
			sum[lson]+=1ll*lazylag[node]*(mid-l+1);
			sum[rson]+=1ll*lazylag[node]*(r-mid);
			lazylag[lson]+=lazylag[node];
			lazylag[rson]+=lazylag[node];
			lazylag[node]=0;
		}
	}
	void build(int node, int l, int r)
	{
	
		lazylag[node]=0;
		if(l == r){
			sum[node]=a[l];
			return ;
		}
		int mid=l+r>>1;
		build(lson,l,mid);
		build(rson,mid+1,r);
		pushup(node);
	}
	void change(int node, int l, int r, int idx,int x)
	{
		if(l==r){
			sum[node]+=x;
			return ;
		}
		spread(node,l,r);
		int mid=l+r>>1;
		if(idx<=mid) change(lson,l,mid,idx,x);
		else change(rson,mid+1,r,idx,x);
		pushup(node);
	}
	void intervalchange(int node, int l, int r, int L,int R,int x)
	{
		if(l==L&&r==R)
		{
			lazylag[node]+=x;
			sum[node]+=1ll*x*(r-l+1);
			return ;
		}
		spread(node,l,r);
		int mid=l+r>>1;
		if(R<=mid) intervalchange(lson,l,mid,L,R,x);
		else if(L>mid) intervalchange(rson,mid+1,r,L,R,x);
		else{
			intervalchange(lson,l,mid,L,mid,x);
			intervalchange(rson,mid+1,r,mid+1,R,x);
		}
		pushup(node);
	}
	ll idquery(int node,int l,int r, int idx)
	{
		if(l==r)
		{
			return sum[node];
		}
		int mid=l+r>>1;
		spread(node,l,r);
		if(mid>=idx)
		return idquery(lson,l,mid,idx);
		else
		return idquery(rson,mid+1,r,idx);
	}
	ll query(int node, int l, int r, int L, int R)
	{
		if(l==L&&r==R)
		{
			return sum[node];
		}
		spread(node,l,r);
		int mid=l+r>>1;
		if(R<=mid) return query(lson, l, mid, L, R);
		else if(L>mid) return query(rson, mid+1,r,L,R);
		else{
			ll ans=0;
			ans+=query(lson,l,mid,L,mid);
			ans+=query(rson,mid+1,r,mid+1,R);
			return ans;
		}
	}
}tree;
int main()
{
	int n,q;
	cin>>n>>q;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	tree.build(1,1,n);
	while(q--)
	{
		int s;
		scanf("%d",&s);
		if(s==1)
		{
			int l,r,x;
			scanf("%d%d%d",&l,&r,&x);
			tree.intervalchange(1,1,n,l,r,x);
		}
		if(s==2)
		{
			int l,r;
			scanf("%d%d",&l,&r);
			printf("%lld\n",tree.query(1,1,n,l,r));
		}
	}
	return 0;
}

3.4派兵布阵

题目链接
题目做法:单点修改,区间求和

#include <bits/stdc++.h>
#define ll long long

using namespace std;

int a[4000000+100];
struct SegmentTree
{
	#define lson (node << 1)
	#define rson (node << 1 | 1)
	static const int N=1e6+10;
	ll sum[N << 2];
	ll lazylag[N<<2];
	void pushup(int node)
	{
		sum[node]=sum[lson]+sum[rson];
	}
	void spread(int node, int l, int r)
	{
		if(lazylag[node])
		{
			int mid=l+r>>1;
			sum[lson]+=1ll*lazylag[node]*(mid-l+1);
			sum[rson]+=1ll*lazylag[node]*(r-mid);
			lazylag[lson]+=lazylag[node];
			lazylag[rson]+=lazylag[node];
			lazylag[node]=0;
		}
	}
	void build(int node, int l, int r)
	{
	
		lazylag[node]=0;
		if(l == r){
			sum[node]=a[l];
			return ;
		}
		int mid=l+r>>1;
		build(lson,l,mid);
		build(rson,mid+1,r);
		pushup(node);
	}
	void change(int node, int l, int r, int idx,int x)
	{
		if(l==r){
			sum[node]+=x;
			return ;
		}
		spread(node,l,r);
		int mid=l+r>>1;
		if(idx<=mid) change(lson,l,mid,idx,x);
		else change(rson,mid+1,r,idx,x);
		pushup(node);
	}
	void intervalchange(int node, int l, int r, int L,int R,int x)
	{
		if(l==L&&r==R)
		{
			lazylag[node]+=x;
			sum[node]+=1ll*x*(r-l+1);
			return ;
		}
		spread(node,l,r);
		int mid=l+r>>1;
		if(R<=mid) intervalchange(lson,l,mid,L,R,x);
		else if(L>mid) intervalchange(rson,mid+1,r,L,R,x);
		else{
			intervalchange(lson,l,mid,L,mid,x);
			intervalchange(rson,mid+1,r,mid+1,R,x);
		}
		pushup(node);
	}
	ll idquery(int node,int l,int r, int idx)
	{
		if(l==r)
		{
			return sum[node];
		}
		int mid=l+r>>1;
		spread(node,l,r);
		if(mid>=idx)
		return idquery(lson,l,mid,idx);
		else
		return idquery(rson,mid+1,r,idx);
	}
	ll query(int node, int l, int r, int L, int R)
	{
		if(l==L&&r==R)
		{
			return sum[node];
		}
		spread(node,l,r);
		int mid=l+r>>1;
		if(R<=mid) return query(lson, l, mid, L, R);
		else if(L>mid) return query(rson, mid+1,r,L,R);
		else{
			ll ans=0;
			ans+=query(lson,l,mid,L,mid);
			ans+=query(rson,mid+1,r,mid+1,R);
			return ans;
		}
	}
}tree;
int main()
{
	int n,q;
    char s[100];
    cin >> q;
    for (int i = 1; i <= q;i++)
    {   
        int sum = 1;
        cin >> n;
        for (int j = 1; j <= n;j++)
        {
            scanf("%d", &a[j]);
        }
        tree.build(1, 1, n);
        while(1)
        {
            getchar();
            scanf("%s", s);
            getchar();
            if (!strcmp(s, "Query"))
            {
                int x, y;
                scanf("%d%d", &x, &y);
                if (sum)
                {
                    printf("Case %d:\n", i);
                    sum = 0;
                }
                printf("%lld\n", tree.query(1, 1, n, x, y));
            }
            else if(!strcmp(s,"Add"))
            {
                int x, y;
                scanf("%d%d", &x, &y);
                tree.change(1, 1, n, x, y);
            }
            else if(!strcmp(s,"Sub"))
            {
                int x, y;
                scanf("%d%d", &x, &y);
                y = y * -1;
                tree.change(1, 1, n, x, y);
            }
            else
                break;
        }
        
    }

        return 0;
}

3.5处理学生

原题链接
题意单点修改,求区间最值
重点是对于pushup函数的修改

void pushup(int node)
	{
		sum[node]=max(sum[lson],sum[rson]);
	}

ac代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

int a[4000000+100];
struct SegmentTree
{
	#define lson (node << 1)
	#define rson (node << 1 | 1)
	static const int N=1e6+10;
	ll sum[N << 2];
	ll lazylag[N<<2];
	void pushup(int node)
	{
		sum[node]=max(sum[lson],sum[rson]);
	}
	void spread(int node, int l, int r)
	{
		if(lazylag[node])
		{
			int mid=l+r>>1;
			sum[lson]+=1ll*lazylag[node]*(mid-l+1);
			sum[rson]+=1ll*lazylag[node]*(r-mid);
			lazylag[lson]+=lazylag[node];
			lazylag[rson]+=lazylag[node];
			lazylag[node]=0;
		}
	}
	void build(int node, int l, int r)
	{
	
		//lazylag[node]=0;
		if(l == r){
			sum[node]=a[l];
			return ;
		}
		int mid=l+r>>1;
		build(lson,l,mid);
		build(rson,mid+1,r);
		pushup(node);
	}
	void change(int node, int l, int r, int idx,int x)
	{
		if(l==r){
            if(x>sum[node])
                sum[node] = x;
            return ;
		}
		//spread(node,l,r);
		int mid=l+r>>1;
		if(idx<=mid) change(lson,l,mid,idx,x);
		else change(rson,mid+1,r,idx,x);
		pushup(node);
	}
	void intervalchange(int node, int l, int r, int L,int R,int x)
	{
		if(l==L&&r==R)
		{
			lazylag[node]+=x;
			sum[node]+=1ll*x*(r-l+1);
			return ;
		}
		spread(node,l,r);
		int mid=l+r>>1;
		if(R<=mid) intervalchange(lson,l,mid,L,R,x);
		else if(L>mid) intervalchange(rson,mid+1,r,L,R,x);
		else{
			intervalchange(lson,l,mid,L,mid,x);
			intervalchange(rson,mid+1,r,mid+1,R,x);
		}
		pushup(node);
	}
	ll idquery(int node,int l,int r, int idx)
	{
		if(l==r)
		{
			return sum[node];
		}
		int mid=l+r>>1;
		spread(node,l,r);
		if(mid>=idx)
		return idquery(lson,l,mid,idx);
		else
		return idquery(rson,mid+1,r,idx);
	}
	ll query(int node, int l, int r, int L, int R)
	{
		if(l==L&&r==R)
		{
			return sum[node];
		}
		spread(node,l,r);
		int mid=l+r>>1;
		if(R<=mid) return query(lson, l, mid, L, R);
		else if(L>mid) return query(rson, mid+1,r,L,R);
		else{
			return max(query(lson,l,mid,L,mid),query(rson,mid+1,r,mid+1,R));
		}
	}
}tree;
int main()
{
    int n, q;
    while(scanf("%d%d", &n, &q)!=EOF)
    {
        for (int i = 1; i <= n;i++)
        scanf("%d", &a[i]);
    tree.build(1, 1, n);
    while(q--)
    {
        char s;
        scanf(" %c ", &s);
        if(s=='Q')
        {
            int x, y;
            scanf("%d%d", &x, &y);
            printf("%lld\n" ,tree.query(1, 1, n, x, y));
        }
        else if(s=='U')
        {
            int x, y;
            scanf("%d%d", &x, &y);
            tree.change(1, 1, n, x, y);
        }
    }
    }
    
    return 0;
}

3.6Minimum Inversion Number

原题链接
题意
每一次将序列的首项放到最后一位
最后输出这个过程中逆序列最小是多少
题解

1:逆序数:i<j,ai>aj,如:4 5 3 2 1,
4的逆序数个数0
5的逆序数个数0
3的逆序数4 5,个数2
2的你叙述4 5 3,个数3
1的逆序数4 5 3 2,个数4
2:离散化的方法
每加入一个数,该位置对应的sum标记1,并更新。
在该位置之后的到n的范围内的1的个数就是这个数的逆序数。
如加入4,逆序数0
加入5,逆序数0
加入3,位置4,5均有1,逆序数为2
加入2,位置3,4,5均有1,逆序数为3
加入1,位置2 3 4 5,逆序数为4.
3最小逆序数对
先求出第一个序列的逆序数,然后用很巧妙的办法求下一个序列的逆序数,直到全部求出;

   序列 4 5 2 1 3 6 ,此序列的逆序数为7,它等到的下一个序列为 5 2 1 3 6 4

   看这个新序列的产生过程,首部删除4,尾部添加4

   删除4,必然会使得这个序列的逆序数减少(4-1)个,因为4前面必定有4-1个数小于4

   添加4,必然会使得这个序列的逆序数增加(6-4)个,因为4后面必定有6-4个数大于4

   由此推出公式,假设移动的数为m,序列的逆序数=上一序列逆序数-(m-1)+(N-m)

因为不太会证明,只能找大佬的来了,原文链接在下面
————————————————
版权声明:本文为CSDN博主「linjiaqingggg」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接
最后附上ac代码

#include <bits/stdc++.h>
#define ll long long

using namespace std;

int a[4000000+100];
struct SegmentTree
{
	#define lson (node << 1)
	#define rson (node << 1 | 1)
	static const int N=1e6+10;
	ll sum[N << 2];
	ll lazylag[N<<2];
	void pushup(int node)
	{
		sum[node]=sum[lson]+sum[rson];
	}
	void spread(int node, int l, int r)
	{
		if(lazylag[node])
		{
			int mid=l+r>>1;
			sum[lson]+=1ll*lazylag[node]*(mid-l+1);
			sum[rson]+=1ll*lazylag[node]*(r-mid);
			lazylag[lson]+=lazylag[node];
			lazylag[rson]+=lazylag[node];
			lazylag[node]=0;
		}
	}
	void build(int node, int l, int r)
	{
	
		//lazylag[node]=0;
		//if(l == r){
		//	sum[node]=a[l];
		//	return ;
		//}
        sum[node] = 0;
        if(l==r)
            return;
        int mid=l+r>>1;
		build(lson,l,mid);
		build(rson,mid+1,r);
		//pushup(node);
	}
	void change(int node, int l, int r, int idx,int x)
	{
		if(l==r){
			sum[node]+=x;
			return ;
		}
		//spread(node,l,r);
		int mid=l+r>>1;
		if(idx<=mid) change(lson,l,mid,idx,x);
		else change(rson,mid+1,r,idx,x);
		pushup(node);
	}
	void intervalchange(int node, int l, int r, int L,int R,int x)
	{
		if(l==L&&r==R)
		{
			lazylag[node]+=x;
			sum[node]+=1ll*x*(r-l+1);
			return ;
		}
		spread(node,l,r);
		int mid=l+r>>1;
		if(R<=mid) intervalchange(lson,l,mid,L,R,x);
		else if(L>mid) intervalchange(rson,mid+1,r,L,R,x);
		else{
			intervalchange(lson,l,mid,L,mid,x);
			intervalchange(rson,mid+1,r,mid+1,R,x);
		}
		pushup(node);
	}
	ll idquery(int node,int l,int r, int idx)
	{
		if(l==r)
		{
			return sum[node];
		}
		int mid=l+r>>1;
		spread(node,l,r);
		if(mid>=idx)
		return idquery(lson,l,mid,idx);
		else
		return idquery(rson,mid+1,r,idx);
	}
	ll query(int node, int l, int r, int L, int R)
	{
		//if(l==L&&r==R)
		//
		//	return sum[node];
		//}
		//spread(node,l,r);
        if(L<=l&&R>=r)
        {
            return sum[node];
        }
        int mid = (l + r) / 2;
        //if(R<=mid) return query(lson, l, mid, L, R);
		//else if(L>mid)
        //    return query(rson, mid + 1, r, L, R);
        //else{
			ll ans=0;
            if(L<=mid)
                ans += query(lson, l, mid, L,R);
            if(R>mid)
                ans += query(rson, mid + 1, r, L, R);
            return ans;
		//}
	}
}tree;
int main()
{
	int n;
    while(scanf("%d",&n)!=EOF)
    {
        tree.build(1, 0, n - 1);
        ll sum = 0;
        for (int i = 0; i < n;i++)
        {
            scanf("%d", &a[i]);
            sum += tree.query(1, 0, n - 1, a[i], n - 1);
            tree.change(1, 0, n - 1, a[i], 1);
        }
                  
        ll minx = sum;
         for (int i = 0; i < n;i++)
        {
            sum += n - 1 - a[i] - a[i];
            minx = min(minx, sum);
        } 
        cout << minx << endl;
    }    
    return 0;
}

3.7Color Count

原题链接
题目大意分两种操作:
1.单点修改:改变点的颜色种类
2.区间查询:输出区间内不重复的颜色个数
做法:因为题目要求的颜色不超过30所以我们可以使用二进制的特点去做。
比如[1,1]存的种类是1就存为1(2进制)种类为2就存为10(2进制)种类为3就存为100(2进制)…对于[1,2]区间就对于[1,1]及[2,2]内的值异或得到的就是[1,2]内的值。询问时对于区间内的值按位&1。如果为真计数器加1。

操作实现

	void pushup(int node)
	{
		sum[node]=sum[lson]|sum[rson];
	}
	void spread(int node, int l, int r)
	{
		if(lazylag[node])
		{
			sum[lson]=lazylag[node];
			sum[rson]=lazylag[node];
			lazylag[lson]=lazylag[node];
			lazylag[rson]=lazylag[node];
			lazylag[node]=0;
		}
	}
	void build(int node, int l, int r)
	{
		if(l == r){
			sum[node]=2;
            lazylag[node]=0;
			return ;
		}
		int mid=l+r>>1;
		build(lson,l,mid);
		build(rson,mid+1,r);
		pushup(node);
	}
	void intervalchange(int node, int l, int r, int L,int R,int x)
	{
		if(l>=L&&r<=R)
		{
            sum[node] = 1 << x;
            lazylag[node] = 1 << x;
            return ;
		}
		spread(node,l,r);
		int mid=l+r>>1;
        if (L <= mid)
            intervalchange(lson, l, mid, L, R, x);
        if (R > mid)
            intervalchange(rson, mid + 1, r, L, R, x);
        pushup(node);
	}
	ll query(int node, int l, int r, int L, int R)
	{
		if(l>=L&&r<=R)
		{
			return sum[node];
		}
		spread(node,l,r);
		int mid=l+r>>1;
        int ans = 0;
        if(R>mid)
            ans |= query(rson, mid + 1, r, L, R);
        if(L<=mid)
            ans |= query(lson, l, mid, L, R);
        return ans;
		
	}

按位&1输出

if(s=='P')
            {
                int l, r;
                scanf("%d%d", &l, &r);
                if(l>r)
                    swap(l, r);
                ll sw = tree.query(1, 1, q, l, r);
                int ans = 0;
                while(sw)
                {
                    if(sw&1)
                        ans++;
                    sw >>= 1;
                }
                printf("%d\n", ans);
            }

ac代码

#include<iostream>
#include<sstream>
#include<iterator>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<vector>
#include<bitset>
#include<climits>
#include<queue>
#include<iomanip>
#include<cmath>
#include<stack>
#include<map>
#include<ctime>
#include<new>
#define ll long long

using namespace std;

int a[4000000+100];
struct SegmentTree
{
	#define lson (node << 1)
	#define rson (node << 1 | 1)
	static const int N=1e6+10;
	ll sum[N << 2];
	ll lazylag[N<<2];
	void pushup(int node)
	{
		sum[node]=sum[lson]|sum[rson];
	}
	void spread(int node, int l, int r)
	{
		if(lazylag[node])
		{
			sum[lson]=lazylag[node];
			sum[rson]=lazylag[node];
			lazylag[lson]=lazylag[node];
			lazylag[rson]=lazylag[node];
			lazylag[node]=0;
		}
	}
	void build(int node, int l, int r)
	{
		if(l == r){
			sum[node]=2;
            lazylag[node]=0;
			return ;
		}
		int mid=l+r>>1;
		build(lson,l,mid);
		build(rson,mid+1,r);
		pushup(node);
	}
	void change(int node, int l, int r, int idx,int x)
	{
		if(l==r){
			sum[node]+=x;
			return ;
		}
		spread(node,l,r);
		int mid=l+r>>1;
		if(idx<=mid) change(lson,l,mid,idx,x);
		else change(rson,mid+1,r,idx,x);
		pushup(node);
	}
	void intervalchange(int node, int l, int r, int L,int R,int x)
	{
		if(l>=L&&r<=R)
		{
            sum[node] = 1 << x;
            lazylag[node] = 1 << x;
            return ;
		}
		spread(node,l,r);
		int mid=l+r>>1;
        if (L <= mid)
            intervalchange(lson, l, mid, L, R, x);
        if (R > mid)
            intervalchange(rson, mid + 1, r, L, R, x);
        pushup(node);
	}
	ll idquery(int node,int l,int r, int idx)
	{
		if(l==r)
		{
			return sum[node];
		}
		int mid=l+r>>1;
		spread(node,l,r);
		if(mid>=idx)
		return idquery(lson,l,mid,idx);
		else
		return idquery(rson,mid+1,r,idx);
	}
	ll query(int node, int l, int r, int L, int R)
	{
		if(l>=L&&r<=R)
		{
			return sum[node];
		}
		spread(node,l,r);
		int mid=l+r>>1;
        int ans = 0;
        if(R>mid)
            ans |= query(rson, mid + 1, r, L, R);
        if(L<=mid)
            ans |= query(lson, l, mid, L, R);
        return ans;
		
	}
}tree;
int main()
{
    int q, p, n;
    while(scanf("%d%d%d",&q,&p,&n)!=EOF)
    {
        tree.build(1, 1, q);
        while(n--)
        {
            char s;
            scanf(" %c", &s);
            if(s=='C')
            {
                int l, r, x;
                scanf("%d%d%d", &l, &r, &x);
                if(l>r)
                    swap(l, r);
                tree.intervalchange(1, 1, q, l, r, x);
            }
            if(s=='P')
            {
                int l, r;
                scanf("%d%d", &l, &r);
                if(l>r)
                    swap(l, r);
                ll sw = tree.query(1, 1, q, l, r);
                int ans = 0;
                while(sw)
                {
                    if(sw&1)
                        ans++;
                    sw >>= 1;
                }
                printf("%d\n", ans);
            }
        }
    }
    return 0;
}

感谢观看

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值