HDU - 4417 Super Mario(高级数据结构)

HDU - 4417 Super Mario

题目描述:给定一个整数序列,有n个数。有m个询问,询问区间[L,R]内小于H的整数有多少个。
输入:第一行是整数T,表示测试用例个数。对每个测试,第一行是整数n,m。下一行是n个整数a1, a2, …, an,后面有m行,每行有3个整数L、R、H。
输出:对每个测试用例,输出m行,每行是一个询问的答案。
数据范围:
1 ≤ L , R < n , m ≤ 100000 , 0 ≤ a i ≤ 1 , 000 , 000 , 000 1≤ L,R < n, m ≤ 100000, 0 ≤ ai ≤1,000,000,000 1L,R<n,m100000,0ai1,000,000,000
1 ≤ H ≤ 1 , 000 , 000 , 000 1 ≤ H ≤1,000,000,000 1H1,000,000,000

题意:给你一段长为n序列,m次询问,询问[L,R]区间内小于等于H的数有多少个。

树状数组: 140MS
主席树: 156MS
划分树: 436MS
分块:358MS

主席树
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6+5;
int n,m;
struct lp{
	int l,r,sum;
}cw[N*20];
int rak[N],ar[N],br[N],tot;
void update(int l,int r,int last,int &cur,int x){
	cw[++tot]=cw[last];
	cw[tot].sum = cw[last].sum + 1;
	cur=tot;
	if(l==r)return;
	int mid=(l+r)>>1;
	if(x<=mid)update(l,mid,cw[last].l,cw[cur].l,x);
	else update(mid+1,r,cw[last].r,cw[cur].r,x);
}
int query(int l,int r,int last,int cur,int k){
	if(l==r)return cw[cur].sum-cw[last].sum;
	int mid=(l+r)>>1;
	if(k<=mid)return query(l,mid,cw[last].l,cw[cur].l,k);
	else {
		int ans=query(mid+1,r,cw[last].r,cw[cur].r,k);
		ans+=cw[cw[cur].l].sum-cw[cw[last].l].sum;
		return ans;
	}
}
int main(){
   	int tim;scanf("%d",&tim);
   	int T=0;
	while(tim--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i){
			scanf("%d",&ar[i]);
			br[i]=ar[i];
		}
		sort(br+1,br+1+n);
		int k=1;
		for(int i=2;i<=n;++i){
			if(br[i]!=br[i-1]){
				br[++k]=br[i];
			}
		}
		tot=0;cw[0].l=cw[0].r=cw[0].sum=0;
		memset(rak,0,sizeof(rak));
		for(int i=1;i<=n;++i){
			int p=lower_bound(br+1,br+1+k,ar[i])-br;
			update(1,k,rak[i-1],rak[i],p);
		}
		printf("Case %d:\n",++T );
		for(int i=0,u,v,w;i<m;++i){
			scanf("%d%d%d",&u,&v,&w);
			u++;v++;
			int p=upper_bound(br+1,br+1+k,w)-br-1;
			if(p)printf("%d\n",query(1,k,rak[u-1],rak[v],p) );
			else printf("0\n");
		}
	}
	return 0;
}

分块
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6+5;
int n,m;
int block,num,belong[N],ls[N],rs[N];
int ar[N];
vector<int>bk[N];
void build(){
	block=3*sqrt(n*1.0);
	num=n/block;if(n%block)num++;
	for(int i=1;i<=n;++i){
		belong[i]=(i-1)/block+1;
	}
	for(int i=1;i<=num;++i){
		ls[i]=(i-1)*block+1;
		rs[i]=i*block;
	}
	rs[num]=n;
	for(int i=0;i<=num;++i)bk[i].clear();
	for(int i=1;i<=n;++i){
		bk[belong[i]].push_back(ar[i]);
	}
	for(int i=1;i<=num;++i){
		sort(bk[i].begin(),bk[i].end());
	}
}
void get(int u,int v,int w){
	int cnt=0;
	if(belong[u]==belong[v]){
		for(int i=u;i<=v;++i){
			if(ar[i]<=w)cnt++;
		}
		printf("%d\n",cnt );
		return;
	}
	for(int i=belong[u]+1;i<belong[v];++i){
		int p=upper_bound(bk[i].begin(),bk[i].end(),w)-bk[i].begin();
		cnt+=(p<0?0:p);
	}
	if(u==ls[belong[u]]){
		int i=belong[u];
		int p=upper_bound(bk[i].begin(),bk[i].end(),w)-bk[i].begin();
		cnt+=(p<0?0:p);		
	}else{
		for(int i=u;i<=rs[belong[u]];++i){
			if(ar[i]<=w)cnt++;
		}
	}
	if(v==rs[belong[v]]){
		int i=belong[v];
		int p=upper_bound(bk[i].begin(),bk[i].end(),w)-bk[i].begin();
		cnt+=(p<0?0:p);
	}else{
		for(int i=ls[belong[v]];i<=v;++i){
			if(ar[i]<=w)cnt++;
		}
	}
	printf("%d\n",cnt );
}
int main(){
   	int tim;scanf("%d",&tim);
   	int T=0;
	while(tim--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i){
			scanf("%d",&ar[i]);
		}
		build();
		printf("Case %d:\n",++T );
		for(int i=0,u,v,w;i<m;++i){
			scanf("%d%d%d",&u,&v,&w);
			get(u+1,v+1,w);
		}
	}
	return 0;
}

树状数组

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
const int N = 1e5+5;
int n,m;
int ar[N],sum[N];
inline int lowbit(int x){
	return x&(-x);
}
inline void add(int x,int d){
	while(x<=n){
		ar[x]+=d;
		x+=lowbit(x);
	}
}
inline int query(int x){
	int ans=0;
	while(x){
		ans+=ar[x];
		x-=lowbit(x);
	}
	return ans;
}
struct lh{
	int val,id;
}br[N];
bool cmp1(lh &a,lh &b){
	if(a.val!=b.val)return a.val<b.val;
	return a.id<b.id;
}
struct lp{
	int l,r,id,val;
}cw[N];
bool cmp2(lp &a,lp &b){
	if(a.val!=b.val)return a.val<b.val;
	return a.id<b.id;
}
int main(){
   	int tim;scanf("%d",&tim);
   	int T=0;
	while(tim--){
		scanf("%d%d",&n,&m);
		for(int i=0;i<n;++i){
			scanf("%d",&br[i].val);
			br[i].id=i+1;
		}
		for(int i=0;i<m;++i){
			scanf("%d%d%d",&cw[i].l,&cw[i].r,&cw[i].val);
			cw[i].l++;cw[i].r++;
			cw[i].id=i+1;
		}
		sort(br,br+n,cmp1);
		sort(cw,cw+m,cmp2);
		memset(ar,0,sizeof(ar));
		for(int i=0,j=0;i<m;++i){
			while(j<n&&br[j].val<=cw[i].val){
				add(br[j].id,1);
				j++;
			}
			sum[cw[i].id]=query(cw[i].r)-query(cw[i].l-1);
		}
		printf("Case %d:\n",++T );
		for(int i=1;i<=m;++i){
			printf("%d\n",sum[i]);
		}
	}
	return 0;
}

划分树

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5+5;
int n,m,sor[N];
struct lp{
	int cnt[N];
	int num[N];
}cw[22];
void build(int l,int r,int d){
	if(l==r)return;
	cw[d].num[0]=cw[d].cnt[0]=0;
	int same=0,mid=(l+r)>>1;
	for(int i=mid;i>=l;--i){
		if(sor[mid]==sor[i])same++;
		else break;
	}
	int lpos=l,rpos=mid+1,cnt=0;
	for(int i=l;i<=r;++i){
		if(cw[d].num[i]<sor[mid]){
			cw[d+1].num[lpos++]=cw[d].num[i];
			cnt++;
		}else if(cw[d].num[i]==sor[mid]&&same){
			same--;cnt++;
			cw[d+1].num[lpos++]=cw[d].num[i];
		}else{
			cw[d+1].num[rpos++]=cw[d].num[i];
		}
		cw[d].cnt[i]=cnt;
	}
	build(l,mid,d+1);
	build(mid+1,r,d+1);
}
int query(int l,int r,int L,int R,int k,int d){
	if(l==r)return cw[d].num[l];
	int mid=(l+r)>>1,newl,newr,left=0,sum_in_left;
	if(l==L){
		sum_in_left=cw[d].cnt[R];
	}else{
		left=cw[d].cnt[L-1];
		sum_in_left=cw[d].cnt[R]-left;
	}
	if(k<=sum_in_left){
		newl=l+left;
		newr=newl+sum_in_left-1;
		return query(l,mid,newl,newr,k,d+1);
	}else{
		newl=mid+L-l+1-left;
		newr=newl+R-L+1-sum_in_left-1;
		return query(mid+1,r,newl,newr,k-sum_in_left,d+1);
	}
}
int main(){
   	int tim;scanf("%d",&tim);
   	int T=0;
	while(tim--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;++i){
			scanf("%d",&sor[i]);
			cw[0].num[i]=sor[i];
		}
		sort(sor+1,sor+1+n);
		build(1,n,0);
		printf("Case %d:\n",++T );
		for(int i=0,u,v,w;i<m;++i){
			scanf("%d%d%d",&u,&v,&w);
			u++;v++;
			int l=1,r=v-u+1,mid,ans=0,tmp;
			while(l<=r){
				mid=(l+r)>>1;
				tmp=query(1,n,u,v,mid,0);
				if(tmp<=w){
					l=mid+1;
					ans=mid;
				}else{
					r=mid-1;
					ans=mid-1;
				}
			}
			printf("%d\n",ans );
		}
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wa_Automata

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值