题解: 线段树区间合并
只需要维护两端 再选正面或反面时4种情况是否满足情况 合并的话 考虑左儿子的右端点 右儿子的左端点的大小关系 然后合并
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <stack> #include <queue> #include <cmath> #include <set> #include <map> #define mp make_pair #define pb push_back #define pii pair<int,int> #define link(x) for(edge *j=h[x];j;j=j->next) #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=3e5+10; const double eps=1e-8; #define ll long long const int inf=1e9; using namespace std; struct edge{int t,v;edge*next;}e[MAXN<<1],*h[MAXN],*o=e; void add(int x,int y,int vul){o->t=y;o->v=vul;o->next=h[x];h[x]=o++;} ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } bool tag[MAXN<<2][4]; int a[MAXN][2]; bool Max(bool t1,bool t2){ if(t1)return true; if(t2)return true; return false; } void up(int rt,int l,int r){ int mid=(l+r)>>1; inc(i,0,3)tag[rt][i]=0; inc(i,0,3)inc(j,0,3){ if(a[2*mid][i&1]<=a[2*mid+1][(j>>1)&1]){ tag[rt][(i&2)+(j&1)]=Max(tag[rt][(i&2)+(j&1)],(tag[rt<<1][i]&tag[rt<<1|1][j])); } } } void built(int rt,int l,int r){ if(l==r){ inc(i,0,3){ if(a[2*l-1][(i>>1)&1]<=a[2*l][i&1])tag[rt][i]=1; } return ; } int mid=(l+r)>>1; built(rt<<1,l,mid); built(rt<<1|1,mid+1,r); up(rt,l,r); } void update(int rt,int l,int r,int t){ if(l==r){ inc(i,0,3){ if(a[2*l-1][(i>>1)&1]<=a[2*l][i&1])tag[rt][i]=1; else tag[rt][i]=0; } return ; } int mid=(l+r)>>1; if(t<=mid)update(rt<<1,l,mid,t); else update(rt<<1|1,mid+1,r,t); up(rt,l,r); } int main(){ int n=read(); inc(i,1,n){ a[i][0]=read(),a[i][1]=read(); if(a[i][0]>a[i][1])swap(a[i][0],a[i][1]); } if(n&1)n++,a[n][0]=a[n][1]=inf; n/=2; built(1,1,n); int m=read(); while(m--){ int x=read();int y=read(); swap(a[x][0],a[y][0]); swap(a[x][1],a[y][1]); update(1,1,n,(x-1)/2+1);update(1,1,n,(y-1)/2+1); bool flag=0; inc(i,0,3)if(tag[1][i])flag=1; if(flag)puts("TAK"); else puts("NIE"); } return 0; }
3526: [Poi2014]Card
Time Limit: 25 Sec Memory Limit: 64 MBSubmit: 409 Solved: 300
[Submit][Status][Discuss]
Description
有n张卡片在桌上一字排开,每张卡片上有两个数,第i张卡片上,正面的数为a[i],反面的数为b[i]。现在,有m个熊孩子来破坏你的卡片了!
第i个熊孩子会交换c[i]和d[i]两个位置上的卡片。
每个熊孩子捣乱后,你都需要判断,通过任意翻转卡片(把正面变为反面或把反面变成正面,但不能改变卡片的位置),能否让卡片正面上的数从左到右单调不降。
Input
第一行一个n。
接下来n行,每行两个数a[i],b[i]。
接下来一行一个m。
接下来m行,每行两个数c[i],d[i]。
Output
m行,每行对应一个答案。如果能成功,输出TAK,否则输出NIE。
Sample Input
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
Sample Output
NIE
TAK
TAK