BZOJ1018 [SHOI2008] 堵塞的交通traffic

@(BZOJ)[线段树]

Description

有一天,由于某种穿越现象作用,你来到了传说中的小人国。小人国的布局非常奇特,整个国家的交通系统可
以被看成是一个\(2\)\(C\)列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道路,所以总共有\(2C\)
城市和\(3C-2\)条道路。 小人国的交通状况非常槽糕。有的时候由于交通堵塞,两座城市之间的道路会变得不连通,
直到拥堵解决,道路才会恢复畅通。初来咋到的你决心毛遂自荐到交通部某份差事,部长听说你来自一个科技高度
发达的世界,喜出望外地要求你编写一个查询应答系统,以挽救已经病入膏肓的小人国交通系统。 小人国的交通
部将提供一些交通信息给你,你的任务是根据当前的交通情况回答查询的问题。交通信息可以分为以下几种格式:
Close r1 c1 r2 c2:相邻的两座城市\((r1,c1)\)\((r2,c2)\)之间的道路被堵塞了;Open r1 c1 r2 c2:相邻的两座城市\((r1,c1)\)\((r2,c2)\)之间的道路被疏通了;Ask r1 c1 r2 c2:询问城市\((r1,c1)\)\((r2,c2)\)是否连通。如果存在一
条路径使得这两条城市连通,则返回Y,否则返回N;

Input

第一行只有一个整数\(C\),表示网格的列数。接下来若干行,每行为一条交通信息,以单独的一行“Exit”作为
结束。我们假设在一开始所有的道路都是堵塞的。我们保证 C小于等于100000,信息条数小于等于\(100000\)

Output

对于每个查询,输出一个“Y”或“N”。

Sample Input

Open 1 1 1 2
Open 1 2 2 2
Ask 1 1 2 2
Ask 2 1 2 2
Exit

Sample Output

Y
N

Solution

這一題還是很難想的, 用的是線段樹維護連通性.

经过分析, \((r1,c1)\)\(\to\)\((r2,c2)\)一共有四种方式。

  1. 直接过去。
  2. 先到\((0,c1)\)再过去。
  3. 先到\((1,c2)\)再过去。
  4. 先到\((0,c1)\)再到\((1,c2)\)再过去。
    用一个数组\(a1[i][j]\),表示x节点维护的区间最左端的第i行能否从区间内部通行到最右端的第j行;
    另一个数组\(a2[i]\)\(a2[0]\)记录x节点维护的区间中最坐端的点能不能从区间内部绕到另外一行, \(a2[1]\)记录最右端的点能不能从区间内部绕到另外一行.

大概就是这样吧, 然后合并两个节点的操作会比较奇怪, 可以直接看代码.

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
inline void read(int &x)
{
    x = 0;
    int flag = 1;
    char c;
    while(! isdigit(c = getchar()))
        if(c == '-')
            flag *= - 1;
    while(isdigit(c))
        x = x * 10 + c - '0', c = getchar();
    x *= flag;
}
inline void read(char *s)
{
    char c;
    while(! isgraph(c = getchar()));
    int len = 0;
    while(isgraph(c))
        s[len ++] = c, c = getchar();
}
void println(int x)
{
    if(x < 0)
        putchar('-'), x *= - 1;
    if(x == 0)
        putchar('0');
    int ans[10 + (1 << 4)], top = 0;
    while(x)
        ans[top ++] = x % 10, x /= 10;
    for(; top; top --)
        putchar(ans[top - 1] + '0');
    putchar('\n');
}
const int C = 1 << 17;
int c;
struct Node
{
    int a1[2][2], a2[2];
}T[C << 2];
int b[C << 2][2];
void Build(int u, int L, int R)
{
    for(int i = 0; i < 2; i ++)
        for(int j = 0; j < 2; j ++)
            T[u].a1[i][j] = T[u].a2[i] = 0;
    if(L == R)
        T[u].a1[0][0] = T[u].a1[1][1] = 1;
    int mid = L + R >> 1;
    if(L < R)
        Build(u << 1, L, mid), Build(u << 1 ^ 1, mid + 1, R);
}
Node Update(Node x1, Node x2, int b[])
{
    Node ret;
    for(int i = 0; i < 2; i ++) 
        for(int j = 0; j < 2; j ++) 
            ret.a1[i][j] = x1.a1[i][0] && b[0] && x2.a1[0][j] || x1.a1[i][1] && b[1] && x2.a1[1][j];
    ret.a2[0]=x1.a2[0] || x1.a1[0][0] && b[0] && x2.a2[0] && b[1] && x1.a1[1][1];
    ret.a2[1]=x2.a2[1] || x2.a1[0][0] && b[0] && x1.a2[1] && b[1] && x2.a1[1][1];    
    return ret;
}
void Change(int k, int u, int L, int R, int r1, int c1, int r2, int c2)
{
    if(r1 == r2 && c1 == L + R >> 1)
        b[u][r1] = k, T[u] = Update(T[u << 1], T[u << 1 | 1], b[u]);
    else if(L == R)
        T[u].a1[0][1] = T[u].a1[1][0] = T[u].a2[0] = T[u].a2[1] = k;
    else
    {
        int mid = L + R >> 1;
        if(c2 <= mid)
            Change(k, u << 1, L, mid, r1, c1, r2, c2);
        else
            Change(k, u << 1 | 1, mid + 1, R, r1, c1, r2, c2);
        T[u] = Update(T[u << 1], T[u << 1 | 1], b[u]);
    }
}
Node Access(int u, int L, int R, int c1, int c2)
{
    int mid = L + R >> 1;
    if(L >= c1 && R <= c2)
        return T[u];
    if(c2 <= mid)
        return Access(u << 1, L, mid, c1, c2);
    else if (c1 > mid)
        return Access(u << 1 | 1, mid + 1, R, c1, c2);
    else
        return Update(Access(u << 1, L, mid, c1, c2), Access(u << 1 | 1, mid + 1, R, c1, c2), b[u]);
}
void Ask(int r1, int c1, int r2, int c2)
{
    Node Left = Access(1, 1, c, 1, c1), Right = Access(1, 1, c, c2, c), Mid = Access(1, 1, c, c1, c2);
    int ret = 0;
    for(int i = 0; i < 2; i ++)
        for(int j = 0; j < 2; j ++)
            if(Mid.a1[i][j] && (i == r1 || Left.a2[1]) && (j == r2 || Right.a2[0]))
            {
                ret = 1;
                break;
            }
    putchar(ret ? 'Y' : 'N');
    putchar('\n');
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("BZOJ1018.in", "r", stdin);
    freopen("BZOJ1018.out", "w", stdout);
    #endif
    read(c);
    char opt[1 << 4];
    Build(1, 1, c);
    while(1)
    {
        read(opt);
        if(opt[0] == 'E')
            return 0;
        int r1, c1, r2, c2;
        read(r1), read(c1), read(r2), read(c2);
        if(c1 > c2)
            swap(r1, r2), swap(c1, c2);
        if(opt[0] == 'O')
            Change(1, 1, 1, c, r1 - 1, c1, r2 - 1, c2);
        else if(opt[0] == 'C')
            Change(0, 1, 1, c, r1 - 1, c1, r2 - 1, c2);
        else
            Ask(r1 - 1, c1, r2 - 1, c2);
    }
}
posted @ 2017-02-22 10:18  Zeonfai  阅读(419)  评论(0编辑  收藏  举报