3526: [Poi2014]Card

3526: [Poi2014]Card

Time Limit: 25 Sec   Memory Limit: 64 MB
Submit: 248   Solved: 178
[ Submit][ Status][ Discuss]

Description

有n张卡片在桌上一字排开,每张卡片上有两个数,第i张卡片上,正面的数为a[i],反面的数为b[i]。现在,有m个熊孩子来破坏你的卡片了!
第i个熊孩子会交换c[i]和d[i]两个位置上的卡片。
每个熊孩子捣乱后,你都需要判断,通过任意翻转卡片(把正面变为反面或把反面变成正面,但不能改变卡片的位置),能否让卡片正面上的数从左到右单调不降。

Input

第一行一个n。
接下来n行,每行两个数a[i],b[i]。
接下来一行一个m。
接下来m行,每行两个数c[i],d[i]。

Output

m行,每行对应一个答案。如果能成功,输出TAK,否则输出NIE。

Sample Input

4
2 5
3 4
6 3
2 7
2
3 4
1 3

Sample Output

NIE
TAK

HINT



【样例解释】

交换3和4后,卡片序列为(2,5) (3,4) (2,7) (6,3),不能成功。

交换1和3后,卡片序列为(2,7) (3,4) (2,5) (6,3),翻转第3张卡片,卡片的正面为2,3,5,6,可以成功。


【数据范围】

n≤200000,m≤1000000,0≤a[i],b[i]≤10000000,1≤c[i],d[i]≤n.

Source

[ Submit][ Status][ Discuss]

用线段树维护区间,具体的就是维护当前节点左端以较小值或较大值开始,右端最小结果是多少,或者无解
这样,交换操作就等价于两个修改操作,直接下去维护就行了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 2E5 + 20;
const int T = 4;

int n,m,c[maxn*T][2],A[maxn*T],B[maxn*T],a[maxn],b[maxn];

int getint()
{
	char ch = getchar(); int ret = 0;
	while (ch < '0' || '9' < ch) ch = getchar();
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret;
}

void maintain(int o)
{
	int lc = (o<<1),rc = (o<<1|1);
	A[o] = A[lc]; B[o] = B[lc];
	
	if (c[lc][0] != -1)
	{
		if (c[lc][0] <= A[rc] && c[rc][0] != -1) c[o][0] = c[rc][0];
		else if (c[lc][0] <= B[rc] && c[rc][1] != -1) c[o][0] = c[rc][1];
		else c[o][0] = -1;
	}
	else c[o][0] = -1;
	
	if (c[lc][1] != -1)
	{
		if (c[lc][1] <= A[rc] && c[rc][0] != -1) c[o][1] = c[rc][0];
		else if (c[lc][1] <= B[rc] && c[rc][1] != -1) c[o][1] = c[rc][1];
		else c[o][1] = -1;
	}
	else c[o][1] = -1;
}

void Build(int o,int l,int r)
{
	if (l == r)
	{
		A[o] = a[l]; B[o] = b[l];
		c[o][0] = a[l]; c[o][1] = b[l];
		return;
	}
	int mid = (l + r) >> 1;
	Build(o<<1,l,mid); Build(o<<1|1,mid+1,r);
	maintain(o);
}

void Modify(int o,int l,int r,int pos)
{
	if (l == r)
	{
		A[o] = a[l]; B[o] = b[l];
		c[o][0] = a[l]; c[o][1] = b[l];
		return;
	}
	int mid = (l + r) >> 1;
	if (pos <= mid) Modify(o<<1,l,mid,pos);
	else Modify(o<<1|1,mid+1,r,pos);
	maintain(o);
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	n = getint();
	for (int i = 1; i <= n; i++)
	{
		a[i] = getint(); b[i] = getint();
		if (a[i] > b[i]) swap(a[i],b[i]);
	}
	
	Build(1,1,n); m = getint();
	while (m--)
	{
		int x = getint(),y = getint();
		swap(a[x],a[y]); swap(b[x],b[y]);
		Modify(1,1,n,x); Modify(1,1,n,y);
		if (c[1][0] != -1) puts("TAK"); else puts("NIE");
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值