• 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))( o)((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('
    ');
    }
    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('
    ');
    }
    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);
        }
    }
    
  • 相关阅读:
    UI复习笔记1
    PHP字符串 集合的相关函数
    PHP的基本知识点
    XMLDictionary 解析的使用
    Json解析
    数据库增 删 改 查
    UICollectionViewFlowLayout自定义
    除了自定义cell以为,还可以通过属性来控制cell线条的长度
    观察者模式
    PHP字符串相关的方法
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/6427655.html
Copyright © 2020-2023  润新知