BZOJ-3526: [Poi2014]Card

[文章目录]

Description

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

对于每段区间,影响其他区间的只有首尾两个元素。记录四种情况是否可行,线段树进行区间合并。时间复杂度O(mlogn+n)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 201000 
int w[N][2];
bool v[N<<2][2][2];
inline char nc()
{
    static char buf[100000],*p1,*p2;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x)
{
    x=0; char ch=nc();
    while(!isdigit(ch)) ch=nc();
    while(isdigit(ch)) x=x*10+ch-'0',ch=nc();
}
inline void ud(int pos,int x,int y)
{
    v[pos][0][0]|=v[pos<<1][0][x]&v[pos<<1|1][y][0];
    v[pos][0][1]|=v[pos<<1][0][x]&v[pos<<1|1][y][1];
    v[pos][1][0]|=v[pos<<1][1][x]&v[pos<<1|1][y][0];
    v[pos][1][1]|=v[pos<<1][1][x]&v[pos<<1|1][y][1];
}
inline void pushup(int pos,int mid)
{
    memset(v[pos],0,sizeof v[pos]);
    if(w[mid][0]<=w[mid+1][0]) ud(pos,0,0);
    if(w[mid][0]<=w[mid+1][1]) ud(pos,0,1);
    if(w[mid][1]<=w[mid+1][0]) ud(pos,1,0);
    if(w[mid][1]<=w[mid+1][1]) ud(pos,1,1);
}
void build(int pos,int l,int r)
{
    if(l==r)
    {
        v[pos][1][1]=v[pos][0][0]=1;
        return ;
    }
    int mid=(l+r)>>1;
    build(pos<<1,l,mid); build(pos<<1|1,mid+1,r);
    pushup(pos,mid);
}
void fix(int pos,int l,int r,int x)
{
    if(l==r) return ;
    int mid=(l+r)>>1;
    if(x<=mid) fix(pos<<1,l,mid,x);
    else fix(pos<<1|1,mid+1,r,x);
    pushup(pos,mid);
}
int main()
{
    int n,m; read(n);
    for(int i=1;i<=n;++i) read(w[i][0]),read(w[i][1]);
    build(1,1,n); read(m); int x,y;
    while(m--)
    {
        read(x); read(y);
        swap(w[x][0],w[y][0]); swap(w[x][1],w[y][1]);
        fix(1,1,n,x); fix(1,1,n,y);
        if(v[1][0][0]|v[1][0][1]|v[1][1][0]|v[1][1][1]) puts("TAK");
        else puts("NIE");
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注