[BZOJ3526][Poi2014]Card 线段树

链接

题意:有一些卡牌,正反各有一个数,你可以任意翻转,每次操作会将两张卡牌的位置调换,你需要在每次操作后回答以现在的卡牌顺序能否通过反转形成一个单调不降的序列

题解

线段树上维护 (f[o][0/1][0/1]) 表示 (o) 这个区间,左边是正面/反面,右边是正面/反面能否形成不降的序列,合并时只要判断 (mid)(mid+1) 的关系即可

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i(a);i<=(b);++i)
using namespace std;
typedef long long ll;
inline int read(){char c;int w;
	while(!isdigit(c=getchar()));w=c&15;
	while(isdigit(c=getchar()))w=w*10+(c&15);return w;
}
inline char smax(int&x,const int&y){return x<y?x=y,1:0;}
inline char smin(int&x,const int&y){return x>y?x=y,1:0;}
const int N=2e5+5,n=read();
int a[N],b[N];
char f[N<<2][2][2];
#define ls o<<1
#define rs o<<1|1
#define pushup()
	REP(p,0,1)REP(q,0,1)f[o][p][q]=0;
	if(a[mid]<=a[mid+1])REP(p,0,1)REP(q,0,1)f[o][p][q]|=f[ls][p][0]&f[rs][0][q];
	if(a[mid]<=b[mid+1])REP(p,0,1)REP(q,0,1)f[o][p][q]|=f[ls][p][0]&f[rs][1][q];
	if(b[mid]<=a[mid+1])REP(p,0,1)REP(q,0,1)f[o][p][q]|=f[ls][p][1]&f[rs][0][q];
	if(b[mid]<=b[mid+1])REP(p,0,1)REP(q,0,1)f[o][p][q]|=f[ls][p][1]&f[rs][1][q];
void update(int o,int l,int r,int x){
	if(l==r)return;int mid=l+r>>1;
	x<=mid?update(ls,l,mid,x):update(rs,mid+1,r,x);
	pushup();
}
inline void build(int o,int l,int r){
	if(l==r){f[o][0][0]=f[o][1][1]=1;return;}
	int mid=l+r>>1;
	build(ls,l,mid),build(rs,mid+1,r);pushup();
}
#define all 1,1,n
int main(){
	REP(i,1,n)a[i]=read(),b[i]=read();
	int m=read();build(all);
	while(m--){
		int x=read(),y=read();swap(a[x],a[y]),swap(b[x],b[y]);
		update(all,x),update(all,y);
		puts(f[1][0][0]||f[1][0][1]||f[1][1][0]||f[1][1][1]?"TAK":"NIE");
	}
	return 0;
}


原文地址:https://www.cnblogs.com/HolyK/p/9884647.html