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