1. 程式人生 > >[BZOJ]3526: [Poi2014]Card

[BZOJ]3526: [Poi2014]Card

ont NPU uil spa 交換 date -- const sin

題解: 線段樹區間合並

只需要維護兩端 再選正面或反面時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

[BZOJ]3526: [Poi2014]Card