树状数组 --一条小咸鱼

树状数组 解决动态前缀和
询问 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;
}

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


tju 3243 Blocked Road
#include <bits/stdc++.h>
using namespace std;
int b[100005],n,zhi[100006];
int lowbit(int x)
{
    return x&(-x);
}
void update(int pos,int num)
{
    while(pos<=n)
    {
        b[pos]+=num;
        pos+=lowbit(pos);
    }
}
int getsum(int pos)
{
    int num=0;
    while(pos>0)
    {
        num+=b[pos];
        pos-=lowbit(pos);
    }
    return num;
}
int main()
{
    int m,i,j,T,a,c,d;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(i=1; i<=n; i++)
        {
            zhi[i]=1;
            b[i]=lowbit(i);
        }
        for(i=1; i<=m; i++)
        {
            scanf("%d",&a);
            if(a==0)
            {
                scanf("%d",&c);
                if(zhi[c]==1)
                {
                    update(c,-1);
                    zhi[c]=0;
                }
                else
                {
                    update(c,1);
                    zhi[c]=1;
                }
            }
            else
            {
                scanf("%d%d",&c,&d);
                if(c>d)
                    swap(c,d);
                if( getsum(d-1)-getsum(c-1)==d-c   ||   getsum(n)-getsum(d-1)+getsum(c-1)==c+n-d )
                    printf("1\n");
                else
                    printf("0\n");
            }
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值