2865. 【集训队互测 2012】Attack (Standard IO)

 

Time Limits: 10000 ms  Memory Limits: 524288 KB  Detailed Limits  

Description

chnlich 非常喜欢玩三国志这款游戏,并喜欢用一些策略出奇制胜。现在,他要开始征服世界的旅途了。他的敌人有N 座城市和N 个太守, N个城市可以看作在二维平面上的N 个点。N 座城市的标号为0,1,2,......,N-1。第i 座城市的坐标为(Xi,Yi),镇守这座城市的太守的能力值为Zi。

chnlich 每次会选择一个边平行于坐标轴的矩形区域,并奇袭其中太守能力值第K小的城市(奇袭结束之后城市与太守依然存在)。

不过,他的敌人经常会偷偷交换两座城市的太守,防止弱点被chnlich 发现。

现在,chnlich 想要知道,每次奇袭时他的敌人的能力值。


 

Input

输入的第一行包含两个整数 N,M,N 表示城市与太守的个数,M 表示接下来发生了 M 个事件。

输入的第二行到第 N+1行,每行包含三个整数,第 i+2行的三个整数依次表示编号为 i 的城市的 Xi,Yi,Zi,含义如题所述。

输入的第 N+2行到第 N+M+1行,每行有两种可能形式:

第一种

QUERY x0 y0 x1 y1 k

表示 chnlich 询问一个相对顶点为(x0,y0),(x1,y1)的矩形中,第 k 小能力值太

守的能力值。

第二种

SWAP x y

表示 chnlich 的敌人交换了编号为 x 和 y 两座城市的太守。


 

Output

对于每一个 QUERY,输出一行。

若不存在第 k 小能力值的太守,输出"It doesn't exist."(不包含引号)。

否则输出一个整数,表示矩形内能力值第 k 小太守的能力值。


 

Sample Input

3 5
1 1 1
2 2 2
3 3 3
QUERY 1 1 3 3 3
SWAP 0 1
QUERY 2 2 4 4 1
SWAP 2 2
QUERY 2 2 3 3 3

Sample Output

3
1
It doesn't exist.

Data Constraint

Hint

对于100%的数据,N<=60000,M<=10000,0<=Xi,Yi,Zi<=10^9,k<=10^9,保证所有操作均合法。

 

题目大意:

在平面内有一些有权点。有m个操作,分为两种,第一种:给定一个矩形区域,问区域内所有点的第k小权值。

第二种:swap x点和y点的权值。

 

题解:

10000ms = 10秒。暴力即可。

把所有点按x坐标升序。

对于第二种操作直接swap , 第一种则先找x坐标在范围内的点,放在一个数组里。然后O(n)找第k小。

 

 

O(n)找序列内的第k小值:

快排。

在快排的基础上加点东西。

每次我们选取一个基准值。把小于此的排在左边 , 大于的在右边。

我们现在找第p小。

如果第p小在左边,排序左边。否则排序右边。

注意:看p是否在左边只需判断p <= j-l+1 

但是看p是否在右边不能直接判断 p > j-l+1,因为i和j之间可能还有元素(狭小缝隙),直接到右边会将其忽略。要判断 p > i-l

如果狭缝正有我们要找的呢? 出现狭缝 :比如序列 1222234 。i在位置2停下 , j在位置5停下。

如果是这样的话 , if语句就会咔嚓掉前面两条判断 ,到第三条语句, 直接更新ans (如下码) 。

还有一种到第三条语句的可能,那就是 递归完了回来 , 但是之前如果答案已经更新 , 再到这里没有意义。return掉。

也就是说,ans只会在狭缝的情况 , 或递归不下去(如下)的情况 , 会更新。

分析时间复杂度:

第一层n,第二层只有n/2 ,然后n/4 , n/8... O(2n)

 

void query(ll L[],ll l,ll r,ll p)
{
	if(l > r) return ;
	ll i=l,j=r;
	ll  mid = L[(l+r)/2];
	while(i<=j)
	{
		while(L[i] < mid) ++i;
		while(L[j] > mid) --j;
		if(i<=j) 
		{
			swap(L[i],L[j]);
			++i,--j;
		}
	}
	if(p > i - l) query(L , i , r , p - (i-l));
	if(j - l + 1>=p)  query(L , l,j,p);
	if(!ans)  ans = L[l+p-1];
}

程序代码:

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define mcy(a,b) memcpy(a,b,sizeof(a))
#define ll long long
#pragma GCC optimize(3)
#define re register
#define inf 2000000000
#define N 60010
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;

struct point
{ll x,y,z,id;}a[N],b[N],c[N]; 

ll n,m,i,j,k,t,ans;
ll fo[N] ,sa[N];
char ch;

bool cmp(point x,point y)
{return x.x < y.x;}

bool tmp(point x,point y)
{return x.z < y.z;}

void init()
{
	ll cnt=0;
	sort(a+1,a+1+n , tmp);
	for(ll i=1;i<=n;i++)
	{
		if(a[i].z!=a[i-1].z) ++cnt;
		fo[cnt] = a[i] . z;
		a[i] . z = cnt;
	}
	
	sort(a+1,a+1+n,cmp);
	for(ll i=1;i<=n;i++) sa[a[i].id] = i;
	return ;
}


ll find1(ll x)
{
	ll l=0,r=n,p=-1;
	while(l<=r)
	{
		ll mid=(l+r)/2;
		if(a[mid] . x >= x) 
		{
			p = mid;
			r = mid - 1;
		}else l = mid+1;
	}
	
	return p ;
}

ll find2(ll x)
{
	ll l=0,r=n,p=-1;
	while(l<=r)
	{
		ll mid=(l+r)/2;
		if(a[mid] . x <= x) 
		{
			p = mid;
			l = mid+1;
		}else r = mid - 1;
	}
	
	return p;
}

ll L[N] , len;

void query(ll L[],ll l,ll r,ll p)
{
	if(l > r) return ;
	ll i=l,j=r;
	ll  mid = L[(l+r)/2];
	while(i<=j)
	{
		while(L[i] < mid) ++i;
		while(L[j] > mid) --j;
		if(i<=j) 
		{
			swap(L[i],L[j]);
			++i,--j;
		}
	}
	if(p > i - l) query(L , i , r , p - (i-l));
	if(j - l + 1>=p)  query(L , l,j,p);
	if(!ans)  ans = L[l+p-1];
}
int main()
{
	scanf("%lld%lld",&n,&m);
	for(i=1;i<=n;i++)
		scanf("%lld%lld%lld\n",&a[i].x,&a[i].y,&a[i].z),a[i].id = i;
		
	init();
	
	for(i=1;i<=m;i++)
	{
		scanf("%c" , &ch);
		if(ch == 'Q')
		{
			ll x1,y1,x2,y2,k;
			scanf("UERY %lld%lld%lld%lld%lld\n",&x1,&y1,&x2,&y2,&k);
			if(x1 > x2) swap(x1,x2);
			if(y1 > y2) swap(y1,y2);
			ll st=find1(x1),ed=find2(x2);
			if(st == -1 || ed == -1)  {printf("It doesn't exist.\n");continue;}
			
			len=0;
			for(j=st;j<=ed;j++)
				if(a[j].y>=y1 && a[j].y<=y2) L[++len] = a[j].z;
			if(len < k )printf("It doesn't exist.\n");else
			{
				ans=0;
				query(L,1,len,k);
				printf("%lld\n",fo[ans] );
				if(fo[ans] == 62872239) 
				{
					len = 0;
					
				}
			}
			
		}
		else
		{
			ll x,y;
			scanf("WAP %lld%lld\n",&x,&y);
			++x;++y;
			swap(a[sa[x]].z , a[sa[y]].z);
		}
	}
}

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值