BZOJ3526[Poi2014]Card——线段树合并

题目描述

有n张卡片在桌上一字排开,每张卡片上有两个数,第i张卡片上,正面的数为a[i],反面的数为b[i]。现在,有m个熊孩子来破坏你的卡片了!
第i个熊孩子会交换c[i]和d[i]两个位置上的卡片。
每个熊孩子捣乱后,你都需要判断,通过任意翻转卡片(把正面变为反面或把反面变成正面,但不能改变卡片的位置),能否让卡片正面上的数从左到右单调不降。

输入

第一行一个n。
接下来n行,每行两个数a[i],b[i]。
接下来一行一个m。
接下来m行,每行两个数c[i],d[i]。

输出

m行,每行对应一个答案。如果能成功,输出TAK,否则输出NIE。

样例输入

4
2 5
3 4
6 3
2 7
2
3 4
1 3

样例输出

NIE
TAK

提示

【样例解释】

交换3和4后,卡片序列为(2,5) (3,4) (2,7) (6,3),不能成功。

交换1和3后,卡片序列为(2,7) (3,4) (2,5) (6,3),翻转第3张卡片,卡片的正面为2,3,5,6,可以成功。

【数据范围】

n≤200000,m≤1000000,0≤a[i],b[i]≤10000000,1≤c[i],d[i]≤n.

 

线段树合并好题。线段树每个节点维护s[x][0/1][0/1],表示x节点对应区间左/右端点选正/背面区间能否单调不减,每次修改后线段树合并,判断根节点的四种情况是否有合法的就行。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
inline char _read()
{
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    int x=0,f=1;char ch=_read();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=_read();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=_read();}
    return x*f;
}
int n,m;
int x,y;
int s[800010][3][3];
int v[400010][3];
void pushup(int rt,int l,int r)
{
    int mid=(l+r)>>1;
    for(int i=0;i<=1;i++)
    {
        for(int j=0;j<=1;j++)
        {   
            s[rt][i][j]=0;
            for(int k=0;k<=1;k++)
            {
                for(int l=0;l<=1;l++)
                {
                    s[rt][i][j]|=s[rt<<1][i][k]&s[rt<<1|1][l][j]&(v[mid][k]<=v[mid+1][l]);
                }
            }
        }
    }
}
void build(int rt,int l,int r)
{
    if(l==r)
    {
        s[rt][0][0]=s[rt][1][1]=1;
        return ;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    pushup(rt,l,r);
}
void change(int rt,int l,int r,int k)
{
    if(l==r)
    {
        s[rt][0][0]=s[rt][1][1]=1;
        return ;
    }
    int mid=(l+r)>>1;
    if(k<=mid)
    {
        change(rt<<1,l,mid,k);
    }
    else
    {
        change(rt<<1|1,mid+1,r,k);
    }
    pushup(rt,l,r);
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        v[i][0]=read();
        v[i][1]=read();
    }
    build(1,1,n);
    m=read();
    for(int i=1;i<=m;i++)
    {
        x=read();
        y=read();
        swap(v[x][0],v[y][0]);
        swap(v[x][1],v[y][1]);
        change(1,1,n,x);
        change(1,1,n,y);
        if(s[1][1][1]|s[1][1][0]|s[1][0][0]|s[1][0][1])
        {
            printf("TAK\n");
        }
        else
        {
            printf("NIE\n");
        }
    }
    return 0;
}
posted @ 2018-09-20 16:29  The_Virtuoso  阅读(160)  评论(0编辑  收藏  举报