POI2014 Card

Card

POI2014

題意

1.有n張卡片,第i張卡片上,正面的數爲a[i],反面的數爲b[i]。

2.有m個操作,第i個操作會交換c[i]和d[i]兩個位置上的卡片

3.每個操作完成後,需要判斷,通過任意翻轉卡片(把正面變爲反面或把反面變成正面,但不能改變卡片的位置),能否讓卡片正面上的數從左到右單調不降。

1.如果沒有交換操作,那麼就是一個線性遞推

2.但是需要多次修改,考慮用線段樹維護

3.合併兩個線段,如果這兩個線段本身都是單調不降的,那麼只要合併處(左邊線段的右端點,右邊線段的左端點)單調不降,那麼整體就是單調不降了

4.每次合併時複雜度爲242^4

5.把交換操作看做兩個單點更新

6.查詢就是整個區間是否存在合法的方案

具體代碼

#include<bits/stdc++.h>
using namespace std;
const int M=200005;
int n,m,A[M][2];
struct Tree {
    bool dp[2][2];
    int L[2],R[2];
} tree[M*4];
void Up(Tree &rt,Tree Ls,Tree Rs) {
    rt.L[0]=Ls.L[0],rt.L[1]=Ls.L[1];
    rt.R[0]=Rs.R[0],rt.R[1]=Rs.R[1];
    for(int i=0; i<2; i++) {
        for(int j=0; j<2; j++) {
            if(Ls.dp[i][0]&&Rs.dp[0][j]&&Ls.R[0]<=Rs.L[0]){
                rt.dp[i][j]=1;
                continue;
            }
            if(Ls.dp[i][0]&&Rs.dp[1][j]&&Ls.R[0]<=Rs.L[1]){
                rt.dp[i][j]=1;
                continue;
            }
            if(Ls.dp[i][1]&&Rs.dp[0][j]&&Ls.R[1]<=Rs.L[0]){
                rt.dp[i][j]=1;
                continue;
            }
            if(Ls.dp[i][1]&&Rs.dp[1][j]&&Ls.R[1]<=Rs.L[1]){
                rt.dp[i][j]=1;
                continue;
            }
            rt.dp[i][j]=0;
        }
    }
}
void build(int L,int R,int p) {
    if(L==R) {
        tree[p].L[0]=tree[p].R[0]=A[L][0];
        tree[p].L[1]=tree[p].R[1]=A[L][1];
        tree[p].dp[0][0]=tree[p].dp[1][1]=1;
        tree[p].dp[0][1]=tree[p].dp[1][0]=0;
        return ;
    }
    int mid=L+R>>1;
    build(L,mid,p<<1);
    build(mid+1,R,p<<1|1);
    Up(tree[p],tree[p<<1],tree[p<<1|1]);
}
void update(int x,int L,int R,int p) {
    if(L==R) {
        tree[p].L[0]=tree[p].R[0]=A[x][0];
        tree[p].L[1]=tree[p].R[1]=A[x][1];
        tree[p].dp[0][0]=tree[p].dp[1][1]=1;
        tree[p].dp[0][1]=tree[p].dp[1][0]=0;
        return ;
    }
    int mid=L+R>>1;
    if(x<=mid)update(x,L,mid,p<<1);
    else update(x,mid+1,R,p<<1|1);
    Up(tree[p],tree[p<<1],tree[p<<1|1]);
}
int main() {
    int x,y;
    scanf("%d",&n);
    for(int i=1; i<=n; i++) {
        scanf("%d %d",&A[i][0],&A[i][1]);
    }
    build(1,n,1);
    scanf("%d",&m);
    for(int i=1; i<=m; i++) {
        scanf("%d %d",&x,&y);
        swap(A[x][0],A[y][0]);
        swap(A[x][1],A[y][1]);
        update(x,1,n,1);
        update(y,1,n,1);
        bool flag=0;
        for(int i=0; i<2; i++) {
            for(int j=0; j<2; j++) {
                if(tree[1].dp[i][j])flag=1;
            }
        }
        if(flag)printf("TAK\n");
        else printf("NIE\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章