NKOJ3777 卡牌操作
问题描述
有n张卡片在桌上一字排开,每张卡片上有两个数,第i张卡片上,正面的数为a[i],反面的数为b[i]。现在,有m个熊孩子来破坏你的卡片了!
第i个熊孩子会交换c[i]和d[i]两个位置上的卡片。
每个熊孩子捣乱后,你都需要判断,通过任意翻转卡片(把正面变为反面或把反面变成正面,但不能改变卡片的位置),能否让卡片正面上的数从左到右单调不降。
输入格式
第一行一个n。
接下来n行,每行两个数a[i],b[i]。
接下来一行一个m。
接下来m行,每行两个数c[i],d[i]。
输出格式
m行,每行对应一个答案。如果能成功,输出TAK,否则输出NIE。
样例输入
4
2 5
3 4
6 3
2 7
2
3 4
1 3
样例输出
NIE
TAK
提示
【样例解释】
交换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.
首先把每个卡片拆成两个点,不妨设其中较小的为 Ai ,较大的为 Bi 。那么如果我们把一左一右满足单调不降的两点间连一条边,那么问题就转换为了能否从1号卡片找到一条能够到达N号卡片的路径。
线段树能够处理一些区间的问题。那么可以考虑能否通过递归的原理,通过两段相邻区间的连通性得出合成的大区间的连通性。
显然我们只需要关心两段区间分别的连通性、两段区间的起止点的值。
首先一个显然的贪心,如果有多种方案使得某一区间连通,那么区间的终点值应该尽可能小。设区间中,从左端点较小值出发能够到达的右端点终点最小值为 VA ,从较大值出发的为 VB ,当前节点为p,左儿子节点为ls,右儿子节点为rs。
p节点的 VA 值将这样被得到:
(1)若ls的 VA 值小于等于rs起点的 A ,那么p节点的
VA 值就是rs的 VA 值;
(2)若不满足(1),但ls的 VA 值小于等于rs起点的 B ,那么p节点的VA 值就是rs的 VB 值;
(3)若上述两项均不满足,显然p代表的区间不可能连通。把p的 VA 置为无穷大即可。
对于 p节点的 VB 值同理。
所以,最终的结论是:
只要根节点的 VA 和 VB 中至少一个不是无穷大,那么就连通。 反之就不连通。
对于熊孩子的操作,单点修改处理,回溯时更新 VA 和 VB 即可。
#include<stdio.h>
#include<algorithm>
#define MAXN 200005
#define MAXT 800005
#define inf 1e9
using namespace std;
int N,M,A[MAXN],B[MAXN];
int a[MAXT],b[MAXT],Va[MAXT],Vb[MAXT];
void Update(int p)
{
int ls=p<<1,rs=ls|1;
if(Va[ls]<=A[a[rs]])Va[p]=Va[rs];
else if(Va[ls]<=B[a[rs]])Va[p]=Vb[rs];
else Va[p]=inf;
if(Vb[ls]<=A[a[rs]])Vb[p]=Va[rs];
else if(Vb[ls]<=B[a[rs]])Vb[p]=Vb[rs];
else Vb[p]=inf;
}
void Build(int p,int x,int y)
{
a[p]=x;b[p]=y;
if(x==y)
{
Va[p]=A[x];Vb[p]=B[x];
return;
}
int mid=x+y>>1;
Build(p<<1,x,mid);
Build(p<<1|1,mid+1,y);
Update(p);
}
void Modify(int p,int k)
{
if(a[p]==b[p]&&a[p]==k)
{
Va[p]=A[k];Vb[p]=B[k];
return;
}
int mid=a[p]+b[p]>>1;
if(k<=mid)Modify(p<<1,k);
if(k>mid)Modify(p<<1|1,k);
Update(p);
}
int main()
{
int i,x,y;
scanf("%d",&N);
for(i=1;i<=N;i++)
{
scanf("%d%d",&x,&y);
if(x>y)swap(x,y);
A[i]=x;B[i]=y;
}
Build(1,1,N);
scanf("%d",&M);
for(i=1;i<=M;i++)
{
scanf("%d%d",&x,&y);
swap(A[x],A[y]);swap(B[x],B[y]);
Modify(1,x);
Modify(1,y);
if(Va[1]==inf&&Vb[1]==inf)puts("NIE");
else puts("TAK");
}
}