[qbzt寒假]线段树和树状数组

树状数组

\(lowbit(x)=x\&(-x)\)

二维树状数组

修改某个点,查询(1,1)到(n,m)的前缀和(树状数组要从1开始)

HDU2642 Stars

\(YFF\)是个浪漫的人,他喜欢数天上的星星。

为了解决这个问题,我们考虑到天空是一个二维平面,有时星星会很亮,有时星星会很暗。首先,天空中没有明亮的星星,然后一些信息会被给出为“\(B\) \(x\) \(y\)”,其中“\(B\)”表示明亮,\(x\)表示\(x\)坐标,\(y\)表示在\((x,y)\)星星是明亮的,而“\(D\) \(x\) \(y\)”中的“\(D\)”表示\((x,y)\)处的恒星是暗淡的。当查询到“\(Q\) \(X1\) \(X2\) \(Y1\)\(Y2\)”时,您应该告诉\(YFF\)该区域有多少明亮的恒星对应于\(X1\)、\(X2\)、\(Y1\)、\(Y2\)这个四边形区域。

\(X,Y (0 <=X,Y<= 1000)\)

二维树状数组模板

#include<cstdio>
#include<algorithm>
#define N 1010
using namespace std;

int c[N][N];
int f[N][N];
int m;

int lowbit(int x){
    return x&(-x);
}

void modify(int x,int y,int z){
    for(int i=x;i<N;i+=lowbit(i)){
        for(int j=y;j<N;j+=lowbit(j)){
            c[i][j]+=z;
        }
    }
}

int query(int x,int y){
    int ret=0;
    for(int i=x;i;i-=lowbit(i)){
        for(int j=y;j;j-=lowbit(j)){
            ret+=c[i][j];
        }
    }
    return ret;
}

int main(){
    scanf("%d",&m);
    while(m--){
        char opt[10];
        int x,y,a,b;
        scanf("%s",opt);
        if(opt[0]=='B'){
            scanf("%d%d",&x,&y);
            x++;y++;
            if(f[x][y]) continue;
            f[x][y]=1;
            modify(x,y,1);
        }
        if(opt[0]=='D'){
            scanf("%d%d",&x,&y);
            x++;y++;
            if(f[x][y]==0) continue;
            f[x][y]=0;
            modify(x,y,-1);
        }
        if(opt[0]=='Q'){
            scanf("%d%d%d%d",&x,&a,&y,&b);
            x++;y++;a++;b++;
            if(x<a) swap(x,a);
            if(y<b) swap(y,b);
            int ans=query(x,y)-query(x,b-1)-query(a-1,y)+query(a-1,b-1);
            printf("%d\n",ans);
        }
    }
    return 0;
}

POJ 2299

先离散化,开一个权值树状数组

POJ 2352

在坐标上有\(n\)个星星,如果某个星星坐标为\((x, y)\), 它的左下位置为:\((x0,y0),x0<=x\) 且\(y0<=y\)。如果左下位置有\(a\)个星星,就表示这个星星属于\(level x\)

按照\(y\)递增,如果\(y\)相同则\(x\)递增的顺序给出\(n\)个星星,求出所有\(level\)水平的数量。

\(x\)为第一关键字升序排序,\(y\)为第二关键字升序排序

计数:排序后,将\(y\)的值一个一个加入树状数组中,加入前维护小于等于这个\(y\)的前缀和,得到的就是\(level\)

CF GYM 100741A Queries

开十个树状数组,分别表示模m=0,1,……的数的个数

每次加减的时候就找到单点修改

BZOJ 3289

树状数组维护区间逆序对

线段树

POJ 3488

裸题

LIS

\(f_i=max\{f_j+1\}\)

线段树优化:1.离散化2.建立线段树,下标代表权值:对于所有$a_k=下标 \(,最大的\)f_k$是多少(线段树维护区间最大值)

BZOJ 1588

\(1.Multiset\)

\(2.\)建立一个权值线段树,对一个值\(x\),二分查找(对下标进行二分查找,寻找下标最大的\(\leq x\)的权值不为\(0\)的点,下标最小的\(\geq x\)的权值不为\(0\)的点,比较差值,取差值较小的)

BZOJ 3211

线段树维护区间和,每次修改暴力分治,如果出现一个区间都是\(0\)或\(1\),打\(tag\),不再修改

Codeforces 718C

操作1:对\([l,r]\)每个矩阵\(*T^x\)

操作2:对\([l,r]\)中的矩阵求和,再\(*[1,1]\)

\(T\)是斐波那契数列数列矩阵加速公式

Codeforces 85D

乍一看与线段树并无关系

1.离散化

2.建立权值线段树

3:

滚动合并:

BZOJ 3339

给出一个序列\(A,Q\)次询问,每次询问在\([Li, Ri]\)的\(mex\)是多少.
\(N, Q ≤ 100000.\)

将所有询问离线下来,按照\(L\)从小到大排序。提前处理好\(1->i\)的前缀\(mex\):

  for(int i=1;i<=n;i++){
        c[a[i]]=1;
        while(c[now]) now++;
        mex[i]=now;
    }

用\(next[i]\)表示下标为\(i\)的数下一次出现在哪个下标:

for(int i=n;i>=1;i--){
        next[i]=last[a[i]];
        if(next[i]==0) next[i]=n+1;
        last[a[i]]=i;
    }

将\(L\)右移一,会将所有\(L+1->next[i]-1\)中\(>A[L]\)的\(mex\)变为\(A[L]\)

然后移动左端点,按照上面进行修改,对右端点进行查询(区间\(mex\)等于最右侧)

BZOJ 2124

给一个\(1\)到\(N\)的排列\(\{Ai\}\),询问是否存在\(1<=p_1<p_2<p_3<p_4<p_5<…<p_{Len}<=N (Len>=3)\),使得\(A_{p1},A_{p2},A_{p3},…A_{pLen}\)是一个等差序列。

实质上问是否存在三元组\((i,j,k)\),满足\(i<j<k\)且\(A_k-A_j=A_j-A_i\)

用二进制表示一个数是否已经选了,在某个位置的数若是\(A[i]\),若其向左数的\(hash\)不等于向右数的\(hash\),说明一定有\(A[i]+x和A[i]-x\)分别在\(A[i]\)所在位置的两边,也就是有解.

↑上面这行目测看不懂,举个例子:

3
3 2 1

这是题目中的数据。我们用\(01\)串表示\(1、2、3\)这三个数选了没有,初始时是\(“0 0 0”\)

从左开始扫描,先选定\(3\),此时\(01\)串表示为\("0 0 1"\),\(3\)的位置在串最右(原数集中\(3\)最大),左右不可能有数和它构成等差序列。

然后选定\(2\),此时\(01\)串表示为“\(0 1 1\)”,以\(2\)的位置为中心向左数,得到\(0\);向右数,在对称位置得到\(1\),这说明“比\(2\)小\(1\)的数”和“比\(2\)大\(1\)的数”一个选了(在左边)一个没选(在右边),那么它们就能构成等差序列了。

存储\(hash\)以判断\(01\)串是否相等,用线段树维护区间\(hash\)以方便查找,就大功告成了。

注意:由于是要判断一个位置左右“对称位置”是否不等,所以要存正序和逆序的\(hash\)。再举个例子:

有\(01\)串:0 1 0 1 [1] 0 1 1 0 1,从中心位置向左数得到的串是“1 0 1 0”,向右数得到的是“0 1 1 0”(两边长度要保持等于最短的一边的长度)。

此处引用Bzoj2124 等差子序列

Luogu 2221

丢一篇题解

原文地址:https://www.cnblogs.com/zhuier-xquan/p/12267051.html

时间: 2024-08-04 17:58:26

[qbzt寒假]线段树和树状数组的相关文章

Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】

弱弱的战壕 描述 永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b. mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作战单位,射程可以达到无限(“mx不赢定了?!?”永恒[email protected][email protected]). 但是,战壕有一个弱点,就是只能攻击它的左下方,说白了就是横纵坐标都不大于它的点(mx:“我的战壕为什么这么菜”ToT).这样,永恒就可以从别的地方进攻摧毁战壕,从而消灭mx的部队. 战壕都有一个保护范围,同它的攻击

Curious Robin Hood(树状数组+线段树)

1112 - Curious Robin Hood    PDF (English) Statistics Forum Time Limit: 1 second(s) Memory Limit: 64 MB Robin Hood likes to loot rich people since he helps the poor people with this money. Instead of keeping all the money together he does another tri

浅谈二维中的树状数组与线段树

一般来说,树状数组可以实现的东西线段树均可胜任,实际应用中也是如此.但是在二维中,线段树的操作变得太过复杂,更新子矩阵时第一维的lazy标记更是麻烦到不行. 但是树状数组在某些询问中又无法胜任,如最值等不符合区间减法的询问.此时就需要根据线段树与树状数组的优缺点来选择了. 做一下基本操作的对比,如下图. 因为线段树为自上向下更新,从而可以使用lazy标记使得矩阵的更新变的高校起来,几个不足就是代码长,代码长和代码长. 对于将将矩阵内元素变为某个值,因为树状数组自下向上更新,且要满足区间加法等限制

[luogu P3801] 红色的幻想乡 [线段树][树状数组]

题目背景 蕾米莉亚的红雾异变失败后,很不甘心. 题目描述 经过上次失败后,蕾米莉亚决定再次发动红雾异变,但为了防止被灵梦退治,她决定将红雾以奇怪的阵势释放. 我们将幻想乡看做是一个n*m的方格地区,一开始没有任何一个地区被红雾遮盖.蕾米莉亚每次站在某一个地区上,向东南西北四个方向各发出一条无限长的红雾,可以影响到整行/整列,但不会影响到她所站的那个地区.如果两阵红雾碰撞,则会因为密度过大而沉降消失.灵梦察觉到了这次异变,决定去解决它.但在解决之前,灵梦想要了解一片范围红雾的密度.可以简述为两种操

【算法系列学习】线段树vs树状数组 单点修改,区间查询 [kuangbin带你飞]专题七 线段树 A - 敌兵布阵

https://vjudge.net/contest/66989#problem/A 单点修改,区间查询 方法一:线段树 http://www.cnblogs.com/kuangbin/archive/2011/08/15/2139834.html 1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<cmath> 6 #

hdu1540 Tunnel Warfare 线段树/树状数组

During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every village was directly con

UVA 11990 ”Dynamic“ Inversion(线段树+树状数组)

[题目链接] UVA11990 [题目大意] 给出一个数列,每次删去一个数,求一个数删去之前整个数列的逆序对数. [题解] 一开始可以用树状数组统计出现的逆序对数量 对于每个删去的数,我们可以用线段树求出它在原序列中的逆序对贡献 在线段树的每个区间有序化数据,就可以二分查找出这个数在每个区间的位置, 这样就处理出了划分出的区间的贡献,先用答案减去这一部分 接下来考虑已经删去部分的容斥,我们发现只要对删去部分再做一次类似的操作, 将这一部分跟当前删去数求一次贡献就是刚才多减去的部分,将这部分的答案

士兵杀敌(四)(树状数组+线段树)

士兵杀敌(四) 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 南将军麾下有百万精兵,现已知共有M个士兵,编号为1~M,每次有任务的时候,总会有一批编号连在一起人请战(编号相近的人经常在一块,相互之间比较熟悉),最终他们获得的军功,也将会平分到每个人身上,这样,有时候,计算他们中的哪一个人到底有多少军功就是一个比较困难的事情,军师小工的任务就是在南将军询问他某个人的军功的时候,快速的报出此人的军功,请你编写一个程序来帮助小工吧. 假设起始时所有人的军功都是0. 输入

Color the ball(树状数组+线段树)

Color the ball Time Limit : 9000/3000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 3   Accepted Submission(s) : 1 Problem Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b