题目描述
有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
2 5
3 4
6 3
2 7
2
3 4
1 3
样例输出
NIE
TAK
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.
线段树合并好题。线段树每个节点维护s[x][0/1][0/1],表示x节点对应区间左/右端点选正/背面区间能否单调不减,每次修改后线段树合并,判断根节点的四种情况是否有合法的就行。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
inline char _read()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
int x=0,f=1;char ch=_read();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=_read();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=_read();}
return x*f;
}
int n,m;
int x,y;
int s[800010][3][3];
int v[400010][3];
void pushup(int rt,int l,int r)
{
int mid=(l+r)>>1;
for(int i=0;i<=1;i++)
{
for(int j=0;j<=1;j++)
{
s[rt][i][j]=0;
for(int k=0;k<=1;k++)
{
for(int l=0;l<=1;l++)
{
s[rt][i][j]|=s[rt<<1][i][k]&s[rt<<1|1][l][j]&(v[mid][k]<=v[mid+1][l]);
}
}
}
}
}
void build(int rt,int l,int r)
{
if(l==r)
{
s[rt][0][0]=s[rt][1][1]=1;
return ;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt,l,r);
}
void change(int rt,int l,int r,int k)
{
if(l==r)
{
s[rt][0][0]=s[rt][1][1]=1;
return ;
}
int mid=(l+r)>>1;
if(k<=mid)
{
change(rt<<1,l,mid,k);
}
else
{
change(rt<<1|1,mid+1,r,k);
}
pushup(rt,l,r);
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
{
v[i][0]=read();
v[i][1]=read();
}
build(1,1,n);
m=read();
for(int i=1;i<=m;i++)
{
x=read();
y=read();
swap(v[x][0],v[y][0]);
swap(v[x][1],v[y][1]);
change(1,1,n,x);
change(1,1,n,y);
if(s[1][1][1]|s[1][1][0]|s[1][0][0]|s[1][0][1])
{
printf("TAK\n");
}
else
{
printf("NIE\n");
}
}
return 0;
}