树状数组 --一条小咸鱼

树状数组 解决动态前缀和
询问 o(n^2)
修改 o(1)

每个位置存储的是一个小区间的值

d[6]=a5+a6
110 2^1个元素
d[8] =a1+…+a8
1000 2^3
在这里插入图片描述
询问14这个位置的前缀和 只需要询问14 12 8 这三个位置
11: 11 10 8 所以只需要将不超过log 的位置的答案加起来就可以
1101 =13 我们要询问13这个位置的前缀和 二进制拆分1101(管辖2^0个元素) 1100 1000 (最多抹掉log个1) 所以修改时要把包含这个这个值的区间都要修改

如 6 (6,8,16 都覆盖了它) 相对于查询 修改相当于把整个位置倒过来
110
查询实在最后一个1的位置减 1
修改是在最后一个1的位置加1
lowbit (int x) return x&(-x);

1100 12
补码 0011+1 0100 通过lowbit 在要查询的几个节点间依次跳跃

int d[100005],n;
int lowbit(int x)
{
return x&(-x)

}
int query(int x)
{
   int res=0;
   while(x)
   {
     res+=d[x];
     x-=lowbit(x);
     
   }
   return res;
   
}
void add(int x,int v)

{
    while(x<=n)
    {d[x]+=v;
    x+=lowbit(x);
    }
}
//对于一个点进行修改 对于一个前缀进行查询

区间加, 单点查询 对区间[3,6] 每个数都加上五 3 位置 加上5 7 位置-5
二位树状数组
单点修改 查询 sum(x,y)
前缀子矩阵 也可以拓展到区间和 (查询4 次前缀和)

struct Bit_2
{

  int d[301][301];
  void update(int x,const int &y,int &v)
  {
    for (;x<=n;x+=lowbit(x))
    for (int j=y;j<=n;j+=(lowbit(j))
    d[x][j]+=v;
  }
  int getsum(int x,const int &y)
  {
 int res=0;
 for (;x;x-=lowbit(x))
 for (int j=y;j;j-=(j&(-j)))
   res+=d[x][j];
  return rs;
  
}
}T;
  

树状数组 区间最值问题 (线段树更好)
树状数组
poj 2352 二维偏序
bzoj 1878 2743 1452
cf round #755 D
ST 表 静态查询区间最值 暴力 o(n^2)
线段树 0(nlog(n)) 单次询问 o(log(n)) 空间0(n)
ST 表 o(nlog(n)) 预处理 单词询问 o(1) 空间 0(nlog(n)) 空间换时间

动态规划 d[i][j] 代表这样一段区间的最值 左端点 i 长度 2^j ,[i,i+2^j-1]

int d[1000006][25];
int mn[1000006];
void rmq_init()
{
    for(int i=1;i<=n;i++)
        d[i][0]=a[i];
    for(int j=1;(1<<j)<=n;j++)
      for(int i=1;i+(1<<j)-1<=n;i++)
        d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
    for(int len=1;len<=n;++len){
        int k=0;
        while((1<<(k+1))<=len)
            k++;
        mn[len]=k;
    }
}
int rmq(int L,int R)
{
    int k=mn[R-L+1];
    return min(d[L][k],d[R-(1<<k)+1][k]);
}

d[5,3]=min(d[5,2],d[9,2])
min(5,12) min(min(5…8),min(9…12))
询问 【5,10】 区间长度 为6
最大 2 的幂次

4
min ([5,8],[7,10])

cdoj 1591

/*
POJ 2352 Stars
就是求每个小星星左小角的星星的个数。坐标按照Y升序,Y相同X升序的顺序给出
由于y轴已经排好序,可以按照x坐标建立一维树状数组
*/
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int MAXN=15010;
const int MAXX=32010;
int c[MAXX];//树状数组的c数组
int cnt[MAXN];//统计结果
int lowbit(int x)
{
    return x&(-x);
}
void add(int i,int val)
{
    while(i<=MAXX)
    {
        c[i]+=val;
        i+=lowbit(i);
    }
}
int sum(int i)
{
    int s=0;
    while(i>0)
    {
        s+=c[i];
        i-=lowbit(i);
    }
    return s;
}
int main()
{
    int n;
    int x,y;
    while(scanf("%d",&n)!=EOF)
    {
        memset(c,0,sizeof(c));
        memset(cnt,0,sizeof(cnt));
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            //加入x+1,是为了避免0,X是可能为0的  可能是 i=0 add(0,1) 会死循环吧 因为 i+=loebit(i) 一直为 0 
            
            int temp=sum(x+1);
            cnt[temp]++;
            add(x+1,1);

        }
        for(int i=0;i<n;i++)
         printf("%d\n",cnt[i]);
    }
    return 0;
}

都没有时间 累死了 今天只写了一点点 题目都没看呢,下次再来啊。

猜你喜欢

转载自blog.csdn.net/weixin_43289491/article/details/89639020