树状数组
P3605 [USACO17JAN] Promotion Counting P
很模板的一道树上树状数组,
计算遍历子树后的变化就可以了,
代码:
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&-x
const int N=2e5+5;
int n,m;
vector<int> g[N];
int a[N],tr[N],cnt[N],p[N];
void change(int x,int k){
while(x<=n){
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;i<g[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<=n;i++){
cin>>p[i];
a[i]=p[i];
}
sort(p+1,p+1+n);
for(int i=1;i<=n;i++) a[i]=lower_bound(p+1,p+1+n,a[i])-p;
for(int i=2;i<=n;i++){
int u;
cin>>u;
g[u].push_back(i);
}
dfs1(1);
for(int i=1;i<=n;i++) cout<<cnt[i]<<endl;
return 0;
}P1972 [SDOI2009] HH 的项链
考虑离线处理,对每次查询按右端点大小排序。
然后从左到右枚举每个贝壳,
如果之前出现了相同的贝壳种类,
由于右端点排序的性质,当前贝壳一定会查询到,
所以给当前贝壳加一,给之前的贝壳减一,来消除区间求和找到它的影响即可。
代码:
#include<bits/stdc++.h>
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){
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.r<y.r;}
signed main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
cin>>m;
for(int i=1;i<=m;i++) cin>>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<=m;i++){
while(l<q[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;i<=m;i++) cout<<ans[i]<<endl;
return 0;
}P4113 [HEOI2012] 采花
思路和上一题很相似,只不过题目改成了区间内同颜色数量大于 2 的颜色个数。
一样的离线+排序,发现从左往右找找到第二个同颜色的点才会对答案有贡献,
所以对于当前点,上一个同颜色的点 +1,上上一个同颜色的点 -1 消除影响即可。
代码:
#include<bits/stdc++.h>
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){
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.r<y.r;}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>c>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++) cin>>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<=m;i++){
while(l<q[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;i<=m;i++) cout<<ans[i]<<"\n";
return 0;
}P4054 [JSOI2009] 计数问题
二维树状数组模板题,建 c 个树状数组即可,代码:
#include<bits/stdc++.h>
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<=n;i+=lowbit(i)) for(int j=y;j<=m;j+=lowbit(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;i<=n;i++) for(int j=1;j<=m;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;
cout<<query(c,x2,y2)-query(c,x1-1,y2)-query(c,x2,y1-1)+query(c,x1-1,y1-1)<<"\n";
}
}
return 0;
}P4514 上帝造题的七分钟
这题需要直接对二维差分数组进行前缀和,
设 为原数组, 为差分数组, 为前缀和数组,有:
然后维护四个二维树状数组即可。
#include<bits/stdc++.h>
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;i<=n;i+=lowbit(i)) for(int j=y;j<=m;j+=lowbit(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;
cout<<check(c,d)-check(a-1,d)-check(c,b-1)+check(a-1,b-1)<<"\n";
}
else break;
}
return 0;
} 

Comments NOTHING