package 树状数组;
//低位操作
//修改操作
//求和
//删除
//插入
//取第K小
public class 模版 {
// 点更新:向上路径更新关键字;
// 区间更新:向下路径更新关键字;
// 更新区间查询点:将inc与get方法互换。
//要注意一个超时陷阱:x==0的情况
static int N;
static int c[]=new int[N];
//要注意一个超时陷阱:x==0的情况
//破解办法有:将要进行统计的数据每一个都加上1,这样就可以避免这种情况
static int lowbit(int i){
int ans=i&(-i);
return ans;
}
//插点问段
static void modify(int k,int d){
while(k<=N){
c[k]+=d;
k+=lowbit(k);
}
}
static int sum(int n){
int result=0;
while(n>0){
result+=c[n];
n-=lowbit(n);
}
return result;
}
//插段问点
static void modify1(int k,int num){
while(k>0){
c[k]+=num;
k-=lowbit(k);
}
}
static int sum1(int n){//用于统计某个点的出现的次数
int s=0;
while(n<=N){
s+=c[n];
n+=lowbit(n);
}
return s;
}
//综上可以看出
//插点问段和插段问点的操作的过程是相反的
//*********************************************
//区间第k小元素,注意值为负数时的需首先离散化
//查询区间不可包含,可以相交,如果包含在处理区间是可能会tle,需谨慎使用此方法。
final int getk(int k) {
int left = 0, right = N, mid, ans = -1;
while (left <= right) {
mid = (left + right) >> 1;
int f = sum(mid);
if (f >= k) {
right = mid - 1;
ans= mid;
} else
left = mid + 1;
}
return ans;
}
}
//***********&&&&&&&&&&&&&&&&&&%%%%%%%%%%%%%%%
int tree[100000];
void iniTree(){memset(tree,0,sizeof(tree));}
inline int Lowbit(int a){return a&-a;}
void ins(int a,int b){//若b==1,插入元素a。若b==-1,删除元素a
while (a<N){
tree[a]+=b;
a+=Lowbit(a+1);
}
}
int findKth(int k){//寻找第k大的元素
int i,j;
i=0;
while (1){
j=0;
while (i<N && tree[i]<k)i+=(j=Lowbit(i+1));
i-=j;
k-=tree[i];
if (!k)break;
++i;
if (Lowbit(i+1)!=1)break;
}
return i;
}
//************************
//*******************************************
对于成段更新的理解:
//比如:(a,b)按段更新,即为先将前b段更新,然后将前a-1段消除更新;
//如前b段加1,则前a-1段减1;
题目推荐:
简单:
POJ 2299 Ultra-QuickSort
POJ 2352 Stars
POJ 1195 Mobile phones
中等
POJ 2155 Matrix
POJ 3321 Apple Tree
POJ 1990 MooFest
难题:
POJ 2464 Brownie Points II
//低位操作
//修改操作
//求和
//删除
//插入
//取第K小
public class 模版 {
// 点更新:向上路径更新关键字;
// 区间更新:向下路径更新关键字;
// 更新区间查询点:将inc与get方法互换。
//要注意一个超时陷阱:x==0的情况
static int N;
static int c[]=new int[N];
//要注意一个超时陷阱:x==0的情况
//破解办法有:将要进行统计的数据每一个都加上1,这样就可以避免这种情况
static int lowbit(int i){
int ans=i&(-i);
return ans;
}
//插点问段
static void modify(int k,int d){
while(k<=N){
c[k]+=d;
k+=lowbit(k);
}
}
static int sum(int n){
int result=0;
while(n>0){
result+=c[n];
n-=lowbit(n);
}
return result;
}
//插段问点
static void modify1(int k,int num){
while(k>0){
c[k]+=num;
k-=lowbit(k);
}
}
static int sum1(int n){//用于统计某个点的出现的次数
int s=0;
while(n<=N){
s+=c[n];
n+=lowbit(n);
}
return s;
}
//综上可以看出
//插点问段和插段问点的操作的过程是相反的
//*********************************************
//区间第k小元素,注意值为负数时的需首先离散化
//查询区间不可包含,可以相交,如果包含在处理区间是可能会tle,需谨慎使用此方法。
final int getk(int k) {
int left = 0, right = N, mid, ans = -1;
while (left <= right) {
mid = (left + right) >> 1;
int f = sum(mid);
if (f >= k) {
right = mid - 1;
ans= mid;
} else
left = mid + 1;
}
return ans;
}
}
//***********&&&&&&&&&&&&&&&&&&%%%%%%%%%%%%%%%
int tree[100000];
void iniTree(){memset(tree,0,sizeof(tree));}
inline int Lowbit(int a){return a&-a;}
void ins(int a,int b){//若b==1,插入元素a。若b==-1,删除元素a
while (a<N){
tree[a]+=b;
a+=Lowbit(a+1);
}
}
int findKth(int k){//寻找第k大的元素
int i,j;
i=0;
while (1){
j=0;
while (i<N && tree[i]<k)i+=(j=Lowbit(i+1));
i-=j;
k-=tree[i];
if (!k)break;
++i;
if (Lowbit(i+1)!=1)break;
}
return i;
}
//************************
//*******************************************
对于成段更新的理解:
//比如:(a,b)按段更新,即为先将前b段更新,然后将前a-1段消除更新;
//如前b段加1,则前a-1段减1;
题目推荐:
简单:
POJ 2299 Ultra-QuickSort
POJ 2352 Stars
POJ 1195 Mobile phones
中等
POJ 2155 Matrix
POJ 3321 Apple Tree
POJ 1990 MooFest
难题:
POJ 2464 Brownie Points II