zoukankan      html  css  js  c++  java
  • bzoj1018 [SHOI2008]堵塞的交通traffic

    1018: [SHOI2008]堵塞的交通traffic

    Time Limit: 3 Sec  Memory Limit: 162 MB
    Submit: 4178  Solved: 1354
    [Submit][Status][Discuss]

    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

    2
    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
    分析:神题一道......
              一眼根本不可做,没告诉具体的图,只告诉一些点的连通信息,这咋做啊......而且能根据连通性确定的边只有一条:(r1,c1)连向(r2,c2)的边.
             方法是利用线段树维护连通性.考虑从(r1,c1)和(r2,c2)通过c1列到c2列的边连通的方法有几种.要么是直接连通,要么是在中间拐了个弯,再过去.这样就很好地利用了线段树的区间合并.对于每一个区间,维护留个变量:a1,a2,b1,b2,c1,c2,分别表示:

                      左上-左下
                      右上-右下
                      左上-右上
                      左下-右下

                      左上-右下
                      左下-右上  是否连通.

    有一个细节需要注意:线段树划分区间是[l,mid],[mid + 1,r],还要维护mid到mid+1之间是否连通.注意,这里维护的区间是相对于列而言的.维护这6个变量就比较容易了,大力讨论,无非就是几种不同的路线嘛,在中间有可能变一下.凭借线段树的向上合并操作,即使只能修改一条边的信息,也能维护整个区间的连通性.

           查询答案有点麻烦.从(r1,c1)走到(r2,c2)可能会走区间[1,c1]和[c2,c],也就是说还要考虑左右两个区间的连通性.设这三个区间分别为pa,pb,pc.(左,中,右).那么路径无非就是4种:1.直接从pb走过去. 2.走pb和pc. 3.走pa和pb. 4.走pa和pb和pc.分别讨论一下就行了. pa和pc只需要考虑上下连通.

           get到新技能,线段树也能维护区间连通性,只是要维护的东西好多好麻烦啊......

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    const int maxn = 100010;
    
    const int dx[] = {0,0,1,-1},dy[] = {1,-1,0,0};
    
    using namespace std;
    int n,r1,c1,r2,c2,flag[maxn][2][2];
    char ch[10];
    //flag[i][0][0]表示i位置第一行是否与i+1位置第一行连通
    //flag[i][1][1]表示第二行.
    //flag[i][0][1]表示同一列上下两行
    
    struct node
    {
        int a1,a2,L,R;
        int b1,b2;
        int c1,c2;
        /*
            左上-左下
            右上-右下
            左上-右上
            左下-右下
            左上-右下
            左下-右上
        */
        void init()
        {
            a1 = a2 = b1 = b2 = c1 = c2 = L = R = 0;
        }
    }e[maxn << 2];
    
    node pushup(node a,node b)
    {
        node c;
        c.init();
        c.L = a.L;
        c.R = b.R;
        int mid = a.R;
        if (a.a1 || (a.b1 && flag[mid][0][0] && flag[mid][1][1] && b.a1 && a.b2))
            c.a1 = 1;
        else
            c.a1 = 0;
        if (b.a2 || (b.b1 && flag[mid][0][0] && flag[mid][1][1] && a.a2 && b.b2))
            c.a2 = 1;
        else
            c.a2 = 0;
        if ((a.b1 && flag[mid][0][0] && b.b1) || (a.c1 && flag[mid][1][1] && b.c2))
            c.b1 = 1;
        else
            c.b1 = 0;
        if ((a.b2 && flag[mid][1][1] && b.b2) || (a.c2 && flag[mid][0][0] && b.c1))
            c.b2 = 1;
        else
            c.b2 = 0;
        if ((a.b1 && flag[mid][0][0] && b.c1) || (a.c1 && flag[mid][1][1] && b.b2))
            c.c1 = 1;
        else
            c.c1 = 0;
        if ((a.b2 && flag[mid][1][1] && b.c2) || (a.c2 && flag[mid][0][0] && b.b1))
            c.c2 = 1;
        else
            c.c2 = 0;
        return c;
    }
    
    void build(int o,int l,int r)
    {
        e[o].init();
        e[o].L = l;
        e[o].R = r;
        if (l == r)
        {
            e[o].b1 = e[o].b2 = 1;
            return;
        }
        int mid = (l + r) >> 1;
        build(o * 2,l,mid);
        build(o * 2 + 1,mid + 1,r);
        e[o] = pushup(e[o * 2],e[o * 2 + 1]);
    }
    
    void update(int o,int l,int r,int pos)
    {
        if (l == r)
        {
            e[o].b1 = e[o].b2 = 1;
            e[o].a1 = e[o].a2 = e[o].c1 = e[o].c2 = flag[l][0][1];
            return;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid)
            update(o * 2,l,mid,pos);
        else
            update(o * 2 + 1,mid + 1,r,pos);
        e[o] = pushup(e[o * 2],e[o * 2 + 1]);
    }
    
    void change(int x)
    {
        int dir = 0;
        for (int i = 0; i < 4; i++)
            if (r1 + dx[i] == r2 && c1 + dy[i] == c2)
            {
                dir = i;
                break;
            }
        if (dir == 0)
        {
            flag[c1][r1][r1] = x;
            update(1,1,n,c1);
        }
        else if (dir == 1)
        {
            flag[c2][r1][r1] = x;
            update(1,1,n,c2);
        }
        else
        {
            flag[c1][0][1] = x;
            update(1,1,n,c1);
        }
    }
    
    node query(int o,int l,int r,int x,int y)
    {
        if (x <= l && r <= y)
            return e[o];
        int mid = (l + r) >> 1;
        if (y <= mid)
            return query(o * 2,l,mid,x,y);
        else
            if (x > mid)
                return query(o * 2 + 1,mid + 1,r,x,y);
        else
            return pushup(query(o * 2,l,mid,x,mid),query(o * 2 + 1,mid + 1,r,mid + 1,y));
    }
    
    void solve()
    {
        if (c1 > c2)
        {
            swap(r1,r2);
            swap(c1,c2);
        }
        node pa = query(1,1,n,1,c1);
        node pb = query(1,1,n,c1,c2);
        node pc = query(1,1,n,c2,n);
        if (r1 == r2)
        {
            if (r1 == 0)
            {
                if (pb.b1 || (pa.a2 && pb.c2) || (pa.a2 && pb.b2 && pc.a1) || (pb.c1 && pc.a1))
                    puts("Y");
                else
                    puts("N");
            }
            else
            {
                if (pb.b2 || (pa.a2 && pb.c1) || (pa.a2 && pb.b1 && pc.a1) || (pb.c2 && pc.a1))
                    puts("Y");
                else
                    puts("N");
            }
        }
        else
        {
            if (r1 == 0)
            {
                if (pb.c1 || (pa.a2 && pb.b2) || (pa.a2 && pb.c2 && pc.a1) || (pb.b1 && pc.a1))
                    puts("Y");
                else
                    puts("N");
            }
            else
            {
                if (pb.c2 || (pa.a2 && pb.b1) || (pa.a2 && pb.c1 && pc.a1) || (pb.b2 && pc.a1))
                    puts("Y");
                else
                    puts("N");
            }
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        build(1,1,n);
        while (1)
        {
            scanf("%s",ch);
            if (ch[0] == 'E')
                break;
            scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
            r1--;
            r2--;
            if (ch[0] == 'A')
                solve();
            if (ch[0] == 'O')
                change(1);
            if (ch[0] == 'C')
                change(0);
        }
    
        return 0;
    }

      

  • 相关阅读:
    【转】Maven 手动添加 JAR 包到本地仓库
    上海畅采电子商务面试题总结
    及善网络科技面试总结
    解析P2P金融的业务安全
    html中返回上一页的各种写法【转】
    Myeclipse 修改Jboss5.x 端口号 8080 改为80
    JavaScript isNaN() 函数的用法
    oracle用户创建及权限设置[转]
    广州亿讯公司(国企)部分题目
    # Java 面试题总结
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8428486.html
Copyright © 2011-2022 走看看