树状数组例题(2019.12.10)

树状数组例题(2019.12.10)

A. Jump

题目描述

有n个障碍物排列在一条直线,障碍物高度为a1,a2,a3…an
有m个独立的询问,一个人最高越过高度为Hi的障碍物,那么在[Li,Ri]区间有多少障碍物是他可以越过的

输入

第一行两个整数n和m(1≤n,m≤1e5)
第二行n个整数,a1,a2,a3…an(1≤ai≤1e9)
余下m行,每行三个整数Li,Ri,Hi(1≤Ri,Li≤n)(1≤Hi≤1e9)

输出

对于每个询问输出一个整数,代表这个人能越过的障碍数量

样例输入

3 3
1 3 2
1 3 1
2 3 1
1 2 4	

输出

1
0
2

源代码

#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
using namespace std;
const int maxn=1e6+7;
const int mod=1e9+7;
struct Quer{
    int l,r,h,id;//保存询问的位置id
    bool operator <(const Quer &a)const{//h从小到大排序
        return h<a.h;
    }
}quer[maxn];
int b[maxn],ans[maxn],tree[maxn],n,m;
pii a[maxn];
void add(int x){
    for(int i=x;i<=n;i+=(i&-i))tree[i]++;
}
int qu(int x){
    int res=0;
    if(x==0)return 0;
    for(int i=x;i;i-=(i&-i))res+=tree[i];
    return res;
}
int main()
{
//        freopen("D:/special1.in","r",stdin);
//        freopen("D:/special1.out","w",stdout);
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++){
            tree[i]=0;
            scanf("%d",&a[i].first);
            a[i].second=i;
        }
        for(int i=1;i<=m;i++){
            scanf("%d %d %d",&quer[i].l,&quer[i].r,&quer[i].h);
            quer[i].id=i;
        }
        sort(a+1,a+1+n);
        sort(quer+1,quer+1+m);//离线处理询问
        int now=1;
        for(int i=1;i<=m;i++){
            //小于h的数,逐个加入树状数组
            while(now<=n&&a[now].first<=quer[i].h){
                add(a[now].second);
                now++;
            }
            ans[quer[i].id]=qu(quer[i].r)-qu(quer[i].l-1);//区间有效值
        }
        for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
	return 0;
}

题解:

B. XOR

题目描述

有一个长度为n的整数序列a1,a2,a3…an,序列元素初始值都为0
需要执行m次以下两种操作
用1 x y表示,把ax修改为y
用2 L R表示,求区间[L,R]的异或和,即aL⊕aL+1⊕aL+2⊕…⊕aR−1⊕aR

输入

第一行两个整数n,m(1≤n≤1e6)(1≤m≤1e5),分别代表序列长度和操作次数
余下m行,每行第一个整数是op,代表操作类型(1≤op≤2)
如果op=1,后面两个数分别为x,y(1≤x,y≤1e6)
如果op=2,后面两个数分别为L,R(1≤L,R≤n)

输出

对于每个第二种操作,输出区间异或和

样例输入

3 5
1 1 9
1 2 8
1 3 7
2 1 3
2 1 2	

输出

6
1

源代码

#include <iostream>
#include <cmath>
using namespace std; 
const int MAX = 1000005;
int tree[MAX], a[MAX], n;

int lowbit(int x)
{
	return x&(-x);
 } 
 
void updata(int x, int k)
{
	if(a[x] != 0)
	{
		for(int i = x; i <= n; i += lowbit(i))
		tree[i] ^= a[x];
	}
		for(int i = x; i <= n; i += lowbit(i))
		tree[i] ^= k;
	a[x] = k;
}

int getsum(int x)
{
	int sum = 0;
	for(int i = x; i > 0; i -= lowbit(i))
	sum ^= tree[i];
	return sum;
}

int main()
{
	int m, x, y, z;
	cin >> n >> m;
	while(m--)
	{
		cin >> z;
		if(z == 1)
		{
			cin >> x >> y;
			updata(x,y);
		}
		if(z == 2)
		{
			int count = 0;
			cin >> x >> y;
			if(y > x)
			{
				count = getsum(y)^getsum(x-1);
				cout << count << endl;
			}
			if(x > y)
			{
				count = getsum(x)^getsum(y-1);
				cout << count << endl;
			}
			if(x == y)
			{
				cout << a[x] << endl;
			}
		}
	}
	return 0;
}

题解:
一个模板题目,把树状数组的加法运算改为xor运算
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值