• 【离线 撤销并查集 线段树分治】bzoj1018: [SHOI2008]堵塞的交通traffic


    本题可化成更一般的问题:离线动态图询问连通性

    当然可以利用它的特殊性质,采用在线线段树维护一些标记的方法

    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”。


    题目分析

    这里提供一种更加一般的模型,即离线动态图连通性。

    大体的思路是:把所有操作都离线之后,对询问分治,将每个询问看做线段树的一个节点(因为询问天然有序),并且记录当前剩余操作(可以是在过程里带vector)。那么这样在处理到每个叶子节点的时候,就已经把有关的操作都执行了。最后离开当前节点时,按栈序撤销并查集操作。

    这个方法的时间复杂度是$O(m log m log n)$($log n$是可撤销并查集的复杂度)。其优化的本质在于,让一段共用边的操作同时处理。

    那么这里有一个很具有启发性的思路:对于一类询问$m$次,每次询问基于若干个元素的问题,可以通过离线分治的方式减少它们的冗余操作,将复杂度将为$O(m log m log n)$。当然最大的缺陷在于必须离线(而且过程里挂vector是不是太占空间了?)

     1 #include<bits/stdc++.h>
     2 const int maxn = 200035;
     3 
     4 struct Edge
     5 {
     6     int u,v,s,t;
     7     Edge(int a=0, int b=0, int c=0, int d=0):u(a),v(b),s(c),t(d) {}
     8 };
     9 int n,qNum,top;
    10 int mp[3][maxn],fat[maxn],size[maxn];
    11 typedef std::vector<Edge> vec;
    12 vec opt;
    13 std::map<int, int> tag[maxn];
    14 std::pair<int, int> qr[maxn],stk[maxn<<2];
    15 char str[5];
    16 
    17 int read()
    18 {
    19     char ch = getchar();
    20     int num = 0, fl = 1;
    21     for (; !isdigit(ch); ch=getchar())
    22         if (ch=='-') fl = -1;
    23     for (; isdigit(ch); ch=getchar())
    24         num = (num<<1)+(num<<3)+ch-48;
    25     return num*fl;
    26 }
    27 int find(int x)
    28 {
    29     while (x!=fat[x]) x = fat[x];
    30     return x;
    31 }
    32 void merge(int x, int y)
    33 {
    34     int fx = find(x), fy = find(y);
    35     if (size[fx] > size[fy]) std::swap(fx, fy);
    36     stk[++top] = std::make_pair(fx, fy);
    37     fat[fx] = fy, size[fy] += size[fx];
    38 }
    39 void cancel()
    40 {
    41     int x = stk[top].first, y = stk[top].second;
    42     fat[x] = x, size[y] -= size[x];
    43 }
    44 void solve(int l, int r, vec opt)
    45 {
    46     vec L,R;
    47     int mid = (l+r)>>1, tmp = top;
    48     for (int i=0, mx=opt.size(); i<mx; i++)
    49     {
    50         int s = opt[i].s, t = opt[i].t;
    51         if (s <= l&&r <= t) merge(opt[i].u, opt[i].v);
    52         else{
    53             if (s <= mid) L.push_back(opt[i]);
    54             if (t > mid) R.push_back(opt[i]);
    55         }
    56     }
    57     if (l==r) puts(find(qr[l].first)==find(qr[l].second)?"Y":"N");
    58     else solve(l, mid, L), solve(mid+1, r, R);
    59     while (tmp!=top) cancel(), --top;
    60 }
    61 int main()
    62 {
    63     n = read();
    64     for (int i=1, cnt=0; i<=n; i++)
    65         mp[1][i] = ++cnt, mp[2][i] = ++cnt;
    66     for (int idx,idy; ;)
    67     {
    68         scanf("%s",str);
    69         if (str[0]=='E') break;
    70         idx = mp[read()][read()], idy = mp[read()][read()];
    71         if (str[0]=='O'){
    72             opt.push_back(Edge(idx, idy, qNum+1, -1));
    73             tag[idx][idy] = tag[idy][idx] = opt.size()-1;
    74         }
    75         if (str[0]=='C') opt[tag[idx][idy]].t = qNum;
    76         if (str[0]=='A') qr[++qNum] = std::make_pair(idx, idy);
    77     }
    78     for (int i=0, mx=opt.size(); i<mx; i++)
    79         if (opt[i].t==-1) opt[i].t = qNum;
    80     for (int i=1; i<=(n<<1); i++) fat[i] = i, size[i] = 1;
    81     solve(1, qNum, opt);
    82     return 0;
    83 }

    END

  • 相关阅读:
    AngularJS:实现动态添加输入控件功能
    Openfire:XMPP的几种消息类型
    Openfire:重新配置openfire
    Clojure:日期操作方法
    Openfire:通过Servlet群发消息
    Openfire:访问Servlet时绕开Openfire的身份验证
    Clojure:解决selmer模板不刷新的问题
    Intellij Idea 13:运行Clojure的repl环境
    MVC.Net 5:允许保存和输出Html内容
    BAE Flask UEditor 使用七牛云
  • 原文地址:https://www.cnblogs.com/antiquality/p/10253684.html
Copyright © 2020-2023  润新知