树状数组专题(入门基础训练)

 

A Simple Problem with Integers

:模板题,区间查询区间更新

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b)	for(int i=a;i>=b;--i)
typedef long long ll;
using namespace std;
const int maxn=5e5+15;
int sum[maxn],a[maxn],b[maxn];
int n;
il void add(int p, int x) {
	while(p <= n+5) sum[p] += x, p += p & -p;
}
il ll ask(int p) {
	ll res = 0;
	while(p) res += sum[p], p -= p & -p;
	return res;
}
il ll r_ask(int l, int r) {
	return ask(r) - ask(l - 1);
}
int main(){
	while(sc(n)!=EOF){
		if(!n)	break;
		rep(i,1,n)	sc(a[i]),b[i]=a[i];
		sort(b+1,b+n+1);
		int sz=unique(b+1,b+1+n)-(b+1);
		rep(i,1,n) a[i]=lower_bound(b+1,b+1+sz,a[i])-b;
		ll ans=0;
		rep(i,1,n){
			ans+=r_ask(a[i]+1,sz);
			add(a[i],1);
		}
		cout<<ans<<endl;
		rep(i,1,n+10) sum[i]=0;	
	}
	return 0;
}

 

Star

题意:定义星星的等级为在它左下角(包括正左和正下)的星星的个数。给出若干个星星的坐标(不超过15000个),输出各个等级的星星分别有多少个。每个星星的坐标不超过32000,输入时按照Y坐标升序输入

思路:这个题目的数据已经不需要你去排序了,都是给好了的,Y坐标已经给定了升序,那我们只要考虑X就行了,每次我们只需要查询X坐标小于等于当前X的即可,注意给的x,y是从0开始的,所以全都++就好了。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
//#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b)	for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-9;
const int maxn=4e4+5;
int sum[maxn],n,ans[maxn];
il void add(int p,int x) { //注意p的上界,容易越界 
	while(p<=32000+5) sum[p]+=x,p+=p&-p;
}
il ll ask(int p) {
	ll res=0;
	while(p) res+=sum[p],p-=p&-p;
	return res;
}
il ll r_ask(int l,int r) {
	return ask(r)-ask(l-1);
}
int x,y;
int main() {
	while(sc(n)!=EOF) {
		rep(i,1,n){
			SC(x,y);
			ans[r_ask(1,++x)]++;
			add(x,1);
		}
		rep(i,0,n-1)	cout<<ans[i]<<endl,ans[i]=0;
		rep(i,0,33000)	sum[i]=0;
	}
	return 0;
}

 

Cows

题意:对于每头牛,吃草的区间在li,ri之间,问在n头牛中,对于第i头牛而言,有几头牛的区间大于这头牛

思路:对于给定的区间进行排序,先按左边界从小到大排序,如果左边界相同,按右边界从大到小排序,这样的话对于一头新来的牛,前面的牛左边界都比他小,所以只要查询有多少大于等于他右边界的即可,注意边界相同的牛即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
//#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b)	for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-9;
const int maxn=1e5+10;
int n,ans[maxn];
struct node{
	int l,r,id;
}a[maxn];
bool cmp(node x,node y){
	if(x.l==y.l)	return x.r>y.r;
	else return x.l<y.l;
}
struct Tree{
	int sum[maxn];
	Tree(){ms(sum,0);}
	void add(int p,int x){
		while(p<=maxn-5) sum[p]+=x,p+=p&-p;
	}
	ll ask(int p){
		ll res=0;
		while(p)	res+=sum[p],p-=p&-p;
		return res;
	}
	ll r_ask(int l,int r){
		return ask(r)-ask(l-1);
	}
};
int main(){
	while(sc(n)!=EOF){
		if(!n)	break;
		rep(i,1,n)	SC(a[i].l,a[i].r),a[i].id=i,a[i].l++,a[i].r++;
		sort(a+1,a+1+n,cmp);
		Tree R;
		rep(i,1,n){
			if(i!=1 && (a[i].l==a[i-1].l && a[i].r==a[i-1].r))
				ans[a[i].id]=ans[a[i-1].id];
			else ans[a[i].id]=R.r_ask(a[i].r,maxn-5);
			R.add(a[i].r,1);
		}
		rep(i,1,n)	cout<<ans[i]<<" ";
		cout<<endl;
	}
	return 0;
}

 

Japan

题意:一个平面,左边自上而下排列了N个点,标号为1,...,N,右边自上而下排列了M个点,标号为1,...,M,它们之间有K条线段相连,每条线段有两个值:x,y,表示该线段连接了左边的标号为x的点和右边的标号为y的点,问有多少个交点(除最初的点外)?

思路:这道题,想一想其实也是排序啦,保证x是递增的,然后对于新来的一条边,我们查询有多少y端点是大于当前的y的,所以我们只需要维护y端点即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
//#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b)	for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-9;
const int maxn=2e3+5;
int T,n,m,k,sum[maxn];
il void add(int p,int x) {
	while(p<=1010) sum[p]+=x,p+=p&-p;
}
il ll ask(int p) {
	ll res=0;
	while(p) res+=sum[p],p-=p&-p;
	return res;
}
il ll r_ask(int l,int r) {
	return ask(r)-ask(l-1);
}
struct node {
	int l,r;
} a[maxn*maxn];
il bool cmp(node x,node y) {
	if(x.l==y.l)	return x.r<y.r;
	else return x.l<y.l;
}
int main() {
	sc(T);
	rep(i,1,T) {
		sc(n),sc(m),sc(k);
		rep(i,1,k)	SC(a[i].l,a[i].r);
		sort(a+1,a+k+1,cmp);
		ll ans=0;
		rep(i,1,k) {
			ans+=r_ask(a[i].r+1,m);
			add(a[i].r,1);
		}
		printf("Test case %d: %lld\n",i,ans);
		ms(sum,0);
	}
	return 0;
}

 

Lost Cows

题意:n头牛,每头牛有[1,n]的独立的编号,现在这些牛杂乱的站在一排,给出在第i头牛之前,并且比第i头牛编号小的个数,i属于2到n。求解现在的每头牛的编号

思路:我们从后往前考虑即可,其实最后一头牛的id都是可以直接确定的,贪心递推即可,点然我们也许可以用树状数组,我是直接用的别人的了,也是从后往前考虑,然后二分当前牛的编号,通过前面比它小的牛和后面比它小的牛来判断即可,树状数组维护的就是当前牛后面比它小的数字。最终该牛的id 是要满足id-1=k(前边比他小的数字个数,已知)+num(后面比它小的数字,树状数组维护)。

//贪心
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
//#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b)	for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-9;
const int maxn=1e5+5;
int n,r[maxn],ans[maxn];
vector<int> tt;
int main() {
	while(sc(n)!=EOF) {
		tt.resize(n+5);
		tt[1]=1;
		rep(i,2,n)	sc(r[i]),tt[i]=i;
		drep(i,n,1) {
			ans[i]=tt[r[i]+1];
			tt.erase(tt.begin()+r[i]+1);
		}
		rep(i,1,n)	cout<<ans[i]<<endl;
		tt.clear();
	}
	return 0;
}
//树状数组
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
//#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b)	for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define MAX 8005
int a[MAX],ans[MAX],tree[MAX],n;
il int ask(int pos){
	int ans=0;
	while(pos>0)	ans+=tree[pos],pos-=pos&(-pos);
	return ans;
}
il void add(int pos,int val){
	while(pos<=n)	tree[pos]+=val,pos+=pos&(-pos);
}
il int solve(int k){
	int left=1,right=n;
	while(left<right){
		int mid=(left+right)>>1;
		int num=ask(mid);
		if(mid-1<num+k) 	left=mid+1;
		else 	right=mid;
	}
	return left;
}
int main() {
	while(sc(n)!=EOF){
		ms(tree,0);
		a[1]=0;
		rep(i,2,n)	sc(a[i]);
		drep(i,n,1){
			int k=solve(a[i]);
			add(k,1);
			ans[i]=k;
		}
		rep(i,1,n)	cout<<ans[i]<<endl;
	}
	return 0;
}

 

Mobile phones

题意:有一个矩阵(初始化为0),给出一些操作:
1 x y a表示在arr[x][y]加上a;
2 l b r t 表示求左上角为(l,b),右下角为(r,t)的矩阵的和。

思路:二维树状数组裸题。单点修改+区间查询。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
//#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b)	for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-9;
const int maxn=2e3+5;
int sum[maxn][maxn],id,a,b,c,d;
il void add(int x,int y,int z){
	int py=y;
	while(x<=maxn-5){
		y=py;
		while(y<=maxn-5)	sum[x][y]+=z,y+=y&-y;
		x+=x&-x;
	} 
}
il ll ask(int x,int y){
	ll res=0,py=y;
	while(x){
		y=py;
		while(y)	res+=sum[x][y],y-=y&-y;	
		x-=x&-x;
	} 
	return res;
}
il ll r_ask(int xa,int ya,int xb,int yb){
	return ask(xb,yb)-ask(xb,ya-1)-ask(xa-1,yb)+ask(xa-1,ya-1);
}
int main(){
	while(sc(id)!=EOF){
		if(id==3)	break;
		else if(id==0)	sc(a),ms(sum,0);
		else if(id==1){
			sc(a),sc(b),sc(c);
			a++,b++,c;
			add(a,b,c);
		}
		else if(id==2){
			SC(a,b),SC(c,d); 
			a++,b++,c++,d++;
			printf("%lld\n",r_ask(a,b,c,d));
		}
	}
	return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值