「
「
「数据结构
」
」
」第
2
2
2章 树状数组
(
(
(前
3
3
3题
)
)
)
目录:
A.单点修改区间查询
B.逆序对
C.严格上升子序列数
A . A. A. 例题 1 1 1 单点修改区间查询
分析:
树状数组模板题 区间和就 前缀和相减
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<bitset>
#define Ctnue continue
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=1e6+5;
int n,m,x,y,z;
ll a[N];
int lowbit(int x){return x&(-x);}
void add(int x,ll k){
for(;x<=n;x+=lowbit(x))
a[x]+=k;
}
ll ques(int x){
ll ans=0;
for(;x;x-=lowbit(x))
ans+=a[x];
return ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
add(i,1ll*x);
}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
if(x==1) add(y,1ll*z);
if(x==2) printf("%lld\n",ques(z)-ques(y-1));
}
return 0;
}
B . B. B. 例题 2 2 2 逆序对
洛谷
l
i
n
k
1
link1
link1 洛谷
l
i
n
k
2
link2
link2
分析:
可用归并排序 但这是树状数组章节
首先要离散化 得出在数组中第几大 然后
树状数组前缀和 那你每次
+
1
+1
+1 不就得出
i
i
i前面有几个数比
i
i
i小 他问你有几个比
i
i
i大的
那就用
i
i
i个数
−
-
− 比
i
i
i小的
=
=
= 比
i
i
i大的 也就是逆序对个数了
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<bitset>
#define Ctnue continue
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=1e5+5;
int tree[N*5],awa[N*5],n;
ll ans;
int lowbit(int x){return x&(-x);}
struct node{
int val,id;
}a[N*5];
bool cmp(node x,node y){
if(x.val==y.val)
return x.id<y.id;
return x.val<y.val;
}
void ins(int p,int x)
{
for(;p<=n;p+=lowbit(p))
tree[p]+=x;
}
int query(int p)
{
int res=0;
for(;p;p-=lowbit(p))
res+=tree[p];
return res;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].val);
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
awa[a[i].id]=i; //离散化
for(int i=1;i<=n;i++)
{
ins(awa[i],1);
ans+=i-query(awa[i]); //当前数量-比i小的
}
printf("%lld",ans);
return 0;
}
C . C. C. 例题 3 3 3 严格上升子序列数
分析:
先弄个
n
3
d
p
:
f
i
,
j
n^3dp:f_{i,j}
n3dp:fi,j表示
i
i
i结尾长度为
j
j
j的严格上升子序列数
f
i
,
j
=
∑
(
a
k
<
a
i
,
k
<
i
)
∗
f
k
,
j
−
1
f_{i,j}=∑(a_k<a_i,k<i)*f_{k,j-1}
fi,j=∑(ak<ai,k<i)∗fk,j−1
然后先离散化 这个
k
k
k就可以树状数组处理了 就是个顺序对
以减法代替
m
o
d
mod
mod会快很多
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<bitset>
#define Ctnue continue
//#pragma GCC optimize(2)
#define reg register
#define K 1000000007
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=1e3+5;
struct node{
int val,id,discr;
}a[N];
int T,n,m;
ll tree[N][N],f[N][N],ans;
int lowbit(int x){return x&(-x);}
bool cmp(node x,node y){return x.val<y.val;}
bool cmp2(node x,node y){return x.id<y.id;}
void Discr() //离散化
{
sort(a+1,a+n+1,cmp);
int tmp=0;
a[1].discr=++tmp;
for(int i=2;i<=n;i++)
{
if(a[i].val==a[i-1].val) a[i].discr=tmp;
else a[i].discr=++tmp;
}
sort(a+1,a+n+1,cmp2);
}
void ins(int p,int locate,int x)
{
for(;p<=n;p+=lowbit(p))
{
tree[p][locate]+=x;
tree[p][locate]%=K;
//if(tree[p][locate]>K) tree[p][locate]-=K; //会快很多
}
}
ll query(int p,int locate)
{
ll res=0;
for(;p;p-=lowbit(p))
{
res+=tree[p][locate];
res%=K;
//if(res>K) res-=K;
}
return res;
}
int main(){
scanf("%d",&T);
int fad=T;
while(T--)
{
ans=0;
memset(tree,0,sizeof(tree));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].val);
a[i].id=i;
}
Discr();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(j==1) f[i][j]=1;
else
{
f[i][j]=query(a[i].discr-1,j-1);
f[i][j]%=K;
//if(f[i][j]>K) f[i][j]-=K;
}
ins(a[i].discr,j,f[i][j]);
}
for(int i=m;i<=n;i++)
{
ans+=f[i][m]; //统计
ans%=K;
//if(ans>K) ans-=K;
}
printf("Case #%d: %lld\n",fad-T,ans);
}
return 0;
}