BZOJ3526[Poi2014]Card——线段树合并
题目描述
有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; }