[BZOJ]3526: [Poi2014]Card

题解: 线段树区间合并

只需要维护两端  再选正面或反面时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 MB
Submit: 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

Sample Output

NIE
TAK
posted @ 2019-02-03 22:58  wang9897  阅读(231)  评论(0编辑  收藏  举报