树状数组
树状数组
P3605 [USACO17JAN] Promotion Counting P
很模板的一道树上树状数组, 计算遍历子树后的变化就可以了, 代码:
#include
using namespace std;
#define lowbit(x) x&-x
const int N=2e5+5;
int n,m;
vector g[N];
int a[N],tr[N],cnt[N],p[N];
void change(int x,int k){
while(x>n;
for(int i=1;i>p[i];
a[i]=p[i];
}
sort(p+1,p+1+n);
for(int i=1;i>u;
g[u].push_back(i);
}
dfs1(1);
for(int i=1;i
`#include
using namespace std;
#define lowbit(x) x&-x
const int N=2e5+5;
int n,m;
vectorint> g[N];
int a[N],tr[N],cnt[N],p[N];
void change(int x,int k){
while(x
tr[x]+=k;
x+=lowbit(x);
}
}
int query(int x){
int t=0;
while(x){
t+=tr[x];
x-=lowbit(x);
}
return t;
}
void dfs1(int x){
cnt[x]-=(query(n)-query(a[x]));
for(int i=0;ig[x].size();i++) dfs1(g[x][i]);
cnt[x]+=(query(n)-query(a[x]));
change(a[x],1);
}
signed main(){
cin>>n;
for(int i=1;i
cin>>p[i];
a[i]=p[i];
}
sort(p+1,p+1+n);
for(int i=1;ia[i]=lower_bound(p+1,p+1+n,a[i])-p;
for(int i=2;i
int u;
cin>>u;
g[u].push_back(i);
}
dfs1(1);
for(int i=1;icnt[i]
return 0;
}`
P1972 [SDOI2009] HH 的项链
考虑离线处理,对每次查询按右端点大小排序。 然后从左到右枚举每个贝壳, 如果之前出现了相同的贝壳种类, 由于右端点排序的性质,当前贝壳一定会查询到, 所以给当前贝壳加一,给之前的贝壳减一,来消除区间求和找到它的影响即可。 代码:
#include
using namespace std;
#define lowbit(x) x&-x
const int N=1e6+5;
int n,m;
int tr[N],a[N],last[N],ans[N];
struct ask{
int l,r,id;
}q[N];
void change(int x,int k){
while(x>n;
for(int i=1;i>a[i];
cin>>m;
for(int i=1;i>q[i].l>>q[i].r,q[i].id=i;
sort(q+1,q+1+m,cmp);
int l=0;
for(int i=1;i
`#include
using namespace std;
#define lowbit(x) x&-x
const int N=1e6+5;
int n,m;
int tr[N],a[N],last[N],ans[N];
struct ask{
int l,r,id;
}q[N];
void change(int x,int k){
while(x
tr[x]+=k;
x+=lowbit(x);
}
}
int query(int x){
int t=0;
while(x){
t+=tr[x];
x-=lowbit(x);
}
return t;
}
bool cmp(ask x,ask y){return x.ry.r;}
signed main(){
cin>>n;
for(int i=1;i>a[i];
cin>>m;
for(int i=1;i>q[i].l>>q[i].r,q[i].id=i;
sort(q+1,q+1+m,cmp);
int l=0;
for(int i=1;i
while(lq[i].r){
l++;
if(last[a[l]]) change(last[a[l]],-1);
last[a[l]]=l;
change(l,1);
}
ans[q[i].id]=query(q[i].r)-query(q[i].l-1);
}
for(int i=1;ians[i]
return 0;
}`
P4113 [HEOI2012] 采花
思路和上一题很相似,只不过题目改成了区间内同颜色数量大于 2 的颜色个数。 一样的离线+排序,发现从左往右找找到第二个同颜色的点才会对答案有贡献, 所以对于当前点,上一个同颜色的点 +1,上上一个同颜色的点 -1 消除影响即可。 代码:
#include
using namespace std;
#define lowbit(x) x&-x
const int N=2e6+5;
int n,m,c;
int tr[N],a[N],last[N],last2[N],ans[N];
struct ask{
int l,r,id;
}q[N];
void change(int x,int k){
while(x>n>>c>>m;
for(int i=1;i>a[i];
for(int i=1;i>q[i].l>>q[i].r,q[i].id=i;
sort(q+1,q+1+m,cmp);
int l=0;
for(int i=1;i
`#include
using namespace std;
#define lowbit(x) x&-x
const int N=2e6+5;
int n,m,c;
int tr[N],a[N],last[N],last2[N],ans[N];
struct ask{
int l,r,id;
}q[N];
void change(int x,int k){
while(x
tr[x]+=k;
x+=lowbit(x);
}
}
int query(int x){
int t=0;
while(x){
t+=tr[x];
x-=lowbit(x);
}
return t;
}
bool cmp(ask x,ask y){return x.ry.r;}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>c>>m;
for(int i=1;i>a[i];
for(int i=1;i>q[i].l>>q[i].r,q[i].id=i;
sort(q+1,q+1+m,cmp);
int l=0;
for(int i=1;i
while(lq[i].r){
l++;
if(!last[a[l]]){
last[a[l]]=l;
continue;
}
change(last[a[l]],1);
if(last2[a[l]]) change(last2[a[l]],-1);
last2[a[l]]=last[a[l]],last[a[l]]=l;
}
ans[q[i].id]=query(q[i].r)-query(q[i].l-1);
}
for(int i=1;ians[i]"\n";
return 0;
}`
P4054 [JSOI2009] 计数问题
二维树状数组模板题,建 c 个树状数组即可,代码:
#include
using namespace std;
#define lowbit(x) x&-x
const int N=105;
int n,m,q;
int tr[N][N*3][N*3],a[N*3][N*3];
void change(int c,int x,int y,int k){
for(int i=x;i=1;i-=lowbit(i)) for(int j=y;j>=1;j-=lowbit(j)) t+=tr[c][i][j];
return t;
}
signed main(){
cin>>n>>m;
for(int i=1;i>a[i][j];
change(a[i][j],i,j,1);
}
cin>>q;
while(q--){
int op;
cin>>op;
if(op==1){
int x,y,c;
cin>>x>>y>>c;
change(a[x][y],x,y,-1);
change(a[x][y]=c,x,y,1);
}
else{
int x1,x2,y1,y2,c;
cin>>x1>>x2>>y1>>y2>>c;
cout
`#include
using namespace std;
#define lowbit(x) x&-x
const int N=105;
int n,m,q;
int tr[N][N*3][N*3],a[N*3][N*3];
void change(int c,int x,int y,int k){
for(int i=x;ilowbit(i)) for(int j=y;jlowbit(j)) tr[c][i][j]+=k;
}
int query(int c,int x,int y){
int t=0;
for(int i=x;i>=1;i-=lowbit(i)) for(int j=y;j>=1;j-=lowbit(j)) t+=tr[c][i][j];
return t;
}
signed main(){
cin>>n>>m;
for(int i=1;ifor(int j=1;j
cin>>a[i][j];
change(a[i][j],i,j,1);
}
cin>>q;
while(q--){
int op;
cin>>op;
if(op==1){
int x,y,c;
cin>>x>>y>>c;
change(a[x][y],x,y,-1);
change(a[x][y]=c,x,y,1);
}
else{
int x1,x2,y1,y2,c;
cin>>x1>>x2>>y1>>y2>>c;
coutquery(c,x2,y2)-query(c,x1-1,y2)-query(c,x2,y1-1)+query(c,x1-1,y1-1)"\n";
}
}
return 0;
}`
P4514 上帝造题的七分钟
这题需要直接对二维差分数组进行前缀和, 设 aa 为原数组,dd 为差分数组,sumsum 为前缀和数组,有:
a[x][y]=∑i=1x∑j=1yd[i][j]sum[x][y]=∑i=1x∑j=1ya[i][j]\begin{aligned} a[x][y]=\sum^{x}{i=1}\sum^{y}{j=1}d[i][j] \ sum[x][y]=\sum^{x}{i=1}\sum^{y}{j=1}a[i][j] \ \end{aligned}
sum[x][y]=∑i=1x∑j=1y∑k=1i∑l=1jd[k][l]=∑i=1x∑j=1y(x−i+1)(y−j+1)d[i][j]=∑i=1x∑j=1yi⋅j⋅d[i][j]−(y+1)∑i=1x∑j=1yi⋅d[i][j]−(x+1)∑i=1x∑j=1yj⋅d[i][j]+(x+1)(y+1)∑i=1x∑j=1yd[i][j] \begin{aligned} &sum[x][y] \ =&\sum^{x}{i=1}\sum^{y}{j=1}\sum^{i}{k=1}\sum^{j}{l=1}d[k][l] \ =&\sum^{x}{i=1}\sum^{y}{j=1}(x-i+1)(y-j+1)d[i][j] \ =&\sum^{x}{i=1}\sum^{y}{j=1}i\cdot j\cdot d[i][j] -(y+1)\sum^{x}{i=1}\sum^{y}{j=1}i\cdot d[i][j] -(x+1)\sum^{x}{i=1}\sum^{y}{j=1}j\cdot d[i][j] +(x+1)(y+1)\sum^{x}{i=1}\sum^{y}{j=1}d[i][j] \end{aligned}
然后维护四个二维树状数组即可。
#include
using namespace std;
#define lowbit(x) x&-x
const int N=2050;
int n,m;
char op;
int a,b,c,d,delta;
int tr1[N][N],tri[N][N],trj[N][N],trij[N][N];
void add(int x,int y,int k){
for(int i=x;i0;i-=lowbit(i)) for(int j=y;j>0;j-=lowbit(j)) res+=(x+1)*(y+1)*tr1[i][j]-(x+1)*trj[i][j]-(y+1)*tri[i][j]+trij[i][j];
return res;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
while(cin>>op){
if(op=='X') cin>>n>>m;
else if(op=='L'){
cin>>a>>b>>c>>d>>delta;
add(a,b,delta),add(a,d+1,-delta),add(c+1,b,-delta),add(c+1,d+1,delta);
}
else if(op=='k'){
cin>>a>>b>>c>>d;
cout
`#include
using namespace std;
#define lowbit(x) x&-x
const int N=2050;
int n,m;
char op;
int a,b,c,d,delta;
int tr1[N][N],tri[N][N],trj[N][N],trij[N][N];
void add(int x,int y,int k){
for(int i=x;ilowbit(i)) for(int j=y;jlowbit(j)) tr1[i][j]+=k,tri[i][j]+=k*x,trj[i][j]+=k*y,trij[i][j]+=k*x*y;
}
int check(int x,int y){
int res=0;
for(int i=x;i>0;i-=lowbit(i)) for(int j=y;j>0;j-=lowbit(j)) res+=(x+1)*(y+1)*tr1[i][j]-(x+1)*trj[i][j]-(y+1)*tri[i][j]+trij[i][j];
return res;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
while(cin>>op){
if(op=='X') cin>>n>>m;
else if(op=='L'){
cin>>a>>b>>c>>d>>delta;
add(a,b,delta),add(a,d+1,-delta),add(c+1,b,-delta),add(c+1,d+1,delta);
}
else if(op=='k'){
cin>>a>>b>>c>>d;
coutcheck(c,d)-check(a-1,d)-check(c,b-1)+check(a-1,b-1)"\n";
}
else break;
}
return 0;
} `