整体二分

OrzOrzOrz

OTZOTZOTZ

%%%%%%%%%%%%

长跪不起


http://www.cnblogs.com/zig-zag/archive/2013/04/18/3027707.html

就在本蒟蒻还在为树套树套树套树怎么写而发愁时(反正就是不会写+懒得写),突然发现了这么个利器。

哈哈哈哈哈哈哈哈哈哈哈哈哈。

以后完全不用写什么高端的数据结构了。

统统离线好了(什么强制在线?不做)。

顺便做了下ZOJ2112POJ2104(一开始狂TLE发现数组开小了,竟然没RE。。。)

一个是动态区间第K大,一个是静态区间第K大。

全都BIT+整体二分,短小精悍。

ZOJ2112:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=50000+5;
const int M=10000+5;
const int inf=1e9;
struct Query{
	int x,y,k,tp,id,cur;
}q[N+M*2],q1[N+M*2],q2[N+M*2];
int a[N],ans[M],tmp[N+M*2],c[N];
int n,m,cnt,num;
inline int lowbit(int x){return x&-x;}
void add(int x,int v){
	for(;x<=n;x+=lowbit(x))c[x]+=v;
}
int sum(int x){
	int ret=0;
	for(;x>0;x-=lowbit(x))ret+=c[x];
	return ret;
}
void divide(int head,int tail,int l,int r){
	if(head>tail)return;
	if(l==r){
		for(int i=head;i<=tail;i++)
		if(q[i].tp==3)ans[q[i].id]=l;
		return;
	}
	int mid=l+r>>1;
	for(int i=head;i<=tail;i++)
	if(q[i].tp==1&&q[i].y<=mid) add(q[i].x,1);
	else 
	if(q[i].tp==2&&q[i].y<=mid) add(q[i].x,-1);
	else 
	if(q[i].tp==3) tmp[i]=sum(q[i].y)-sum(q[i].x-1);
	
	for(int i=head;i<=tail;i++)
	if(q[i].tp==1&&q[i].y<=mid) add(q[i].x,-1);
	else 
	if(q[i].tp==2&&q[i].y<=mid) add(q[i].x,1);
	int l1=0,l2=0;
	for(int i=head;i<=tail;i++)
	if(q[i].tp==3){
		if(q[i].cur+tmp[i]>q[i].k-1)q1[++l1]=q[i];
		else q[i].cur+=tmp[i],q2[++l2]=q[i];
	}else{
		if(q[i].y<=mid)q1[++l1]=q[i];
		else q2[++l2]=q[i];
	}
	for(int i=1;i<=l1;i++)q[head+i-1]=q1[i];
	for(int i=1;i<=l2;i++)q[head+i-1+l1]=q2[i];
	divide(head,head+l1-1,l,mid);
	divide(head+l1,tail,mid+1,r);
}
int main(){
	int X;scanf("%d",&X);
	while(X--){
		scanf("%d%d",&n,&m);
		cnt=0;num=0;
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			q[++cnt].x=i;q[cnt].y=a[i];q[cnt].tp=1;
		}
		int x,y,k;char opt[10];
		for(int i=1;i<=m;i++){
			scanf("%s",opt);
			if(opt[0]=='Q'){
				scanf("%d%d%d",&x,&y,&k);
				q[++cnt].x=x;q[cnt].y=y;q[cnt].k=k;q[cnt].cur=0;q[cnt].id=++num;q[cnt].tp=3;
			}else{
				scanf("%d%d",&x,&y);
				q[++cnt].x=x;q[cnt].y=a[x];q[cnt].tp=2;
				q[++cnt].x=x;q[cnt].y=y;q[cnt].tp=1;
				a[x]=y;
			}
		}
		divide(1,cnt,0,inf);
		for(int i=1;i<=num;i++)
		printf("%d\n",ans[i]);
	}
	return 0;
}
POJ2104:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int inf=1e9;
const int N=100000+5;
const int M=5000+5;
struct Query{
	int x,y,k,id,tp,cur;
}q[N+M],q1[N+M],q2[N+M];
int ans[M],tmp[N+M],d[N];
int n,m,cnt;
inline int lowbit(int x){return x&-x;}
void add(int x,int v){
	for(;x<=n;x+=lowbit(x))d[x]+=v;
}
int sum(int x){
	int ret=0;
	for(;x>0;x-=lowbit(x))ret+=d[x];
	return ret;
}
void divide(int head,int tail,int l,int r){
	if(head>tail)return;
	if(l==r){
		for(int i=head;i<=tail;i++)
		if(q[i].tp==2)ans[q[i].id]=l;
		return;
	}
	int mid=l+(r-l)/2;
	for(int i=head;i<=tail;i++)
	if(q[i].tp==1&&q[i].y<=mid)add(q[i].x,1);
	else if(q[i].tp==2)tmp[i]=sum(q[i].y)-sum(q[i].x-1);
	for(int i=head;i<=tail;i++)
	if(q[i].tp==1&&q[i].y<=mid)add(q[i].x,-1);
	int l1=0,l2=0;
	for(int i=head;i<=tail;i++)
	if(q[i].tp==2){
		if(q[i].cur+tmp[i]>q[i].k-1)q1[++l1]=q[i];
		else	q[i].cur+=tmp[i],q2[++l2]=q[i];
	}else{
		if(q[i].y<=mid)q1[++l1]=q[i];
		else q2[++l2]=q[i];
	}
	for(int i=1;i<=l1;i++)q[head+i-1]=q1[i];
	for(int i=1;i<=l2;i++)q[head+i+l1-1]=q2[i];
	divide(head,head+l1-1,l,mid);
	divide(head+l1,tail,mid+1,r);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		q[++cnt].x=i;scanf("%d",&q[cnt].y);
		q[cnt].tp=1;
	}
	for(int i=1;i<=m;i++){
		q[++cnt].id=i;
		scanf("%d%d%d",&q[cnt].x,&q[cnt].y,&q[cnt].k);
		q[cnt].tp=2;
	}
	divide(1,cnt,-inf,inf);
	for(int i=1;i<=m;i++)
	printf("%d\n",ans[i]);
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值