[POI2014]Cards
题目大意:
有$n(n\le2\times10^5)$张卡片排成一排,每张卡片正反面有两个数$a_i$和$b_i$。$m(m\le10^6)$次操作,每次交换第$c_i$和第$d_i$张卡片,问若可以任意翻转卡片,是否存在一种方案使得卡片上的数字构成一个不下降序列。
思路:
用线段树维护区间,左端点取最大/小值时,右端点取最大值还是最小值。
1 #include<cstdio> 2 #include<cctype> 3 #include<algorithm> 4 inline int getint() { 5 register char ch; 6 while(!isdigit(ch=getchar())); 7 register int x=ch^'0'; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 9 return x; 10 } 11 const int N=200001; 12 int a[N][2]; 13 class SegmentTree { 14 #define _left <<1 15 #define _right <<1|1 16 private: 17 int val[N<<2][2]; 18 void push_up(const int &p,const int &b,const int &e) { 19 const int mid=(b+e)>>1; 20 val[p][0]=val[p][1]=-1; 21 if(val[p _left][0]==-1) return; 22 if(a[mid+1][1]>=a[mid][val[p _left][0]]) val[p][0]=val[p _right][1]; 23 if(a[mid+1][0]>=a[mid][val[p _left][0]]) val[p][0]=val[p _right][0]; 24 if(val[p _left][1]==-1) return; 25 if(a[mid+1][1]>=a[mid][val[p _left][1]]) val[p][1]=val[p _right][1]; 26 if(a[mid+1][0]>=a[mid][val[p _left][1]]) val[p][1]=val[p _right][0]; 27 } 28 public: 29 void build(const int &p,const int &b,const int &e) { 30 if(b==e) { 31 val[p][0]=0; 32 val[p][1]=1; 33 return; 34 } 35 const int mid=(b+e)>>1; 36 build(p _left,b,mid); 37 build(p _right,mid+1,e); 38 push_up(p,b,e); 39 } 40 void modify(const int &p,const int &b,const int &e,const int &x) { 41 if(b==e) return; 42 const int mid=(b+e)>>1; 43 if(x<=mid) modify(p _left,b,mid,x); 44 if(x>mid) modify(p _right,mid+1,e,x); 45 push_up(p,b,e); 46 } 47 bool query() const { 48 return val[1][0]!=-1; 49 } 50 #undef _left 51 #undef _right 52 }; 53 SegmentTree t; 54 int main() { 55 const int n=getint(); 56 for(register int i=1;i<=n;i++) { 57 a[i][0]=getint(),a[i][1]=getint(); 58 if(a[i][0]>a[i][1]) std::swap(a[i][0],a[i][1]); 59 } 60 t.build(1,1,n); 61 for(register int m=getint();m;m--) { 62 const int x=getint(),y=getint(); 63 std::swap(a[x][0],a[y][0]); 64 std::swap(a[x][1],a[y][1]); 65 t.modify(1,1,n,x); 66 t.modify(1,1,n,y); 67 puts(t.query()?"TAK":"NIE"); 68 } 69 return 0; 70 }