zoukankan      html  css  js  c++  java
  • 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);
        }
    }
    
  • 相关阅读:
    java的构造方法 java程序员
    No result defined for action cxd.action.QueryAction and result success java程序员
    大学毕业后拉开差距的真正原因 java程序员
    hibernate的回滚 java程序员
    验证码 getOutputStream() has already been called for this response异常的原因和解决方法 java程序员
    浅谈ssh(struts,spring,hibernate三大框架)整合的意义及其精髓 java程序员
    你平静的生活或许会在某个不可预见的时刻被彻底打碎 java程序员
    Spring配置文件中使用ref local与ref bean的区别. 在ApplicationResources.properties文件中,使用<ref bean>与<ref local>方法如下 java程序员
    poj1416Shredding Company
    poj1905Expanding Rods
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/6427655.html
Copyright © 2011-2022 走看看