zoukankan      html  css  js  c++  java
  • Gym 100851 Distance on Triangulation

    题意:给你一个N边形, 然后这个n边形有n-3条边,然后询问2点之间的最短路。

    题解:分治。

    我们可以找到一条边,使得这幅图能分成大小相同的2幅图,那么我们就可以确定那些被分割开的询问的答案是多少了。

    我们假定u v是分开的, 然后我们从u点bfs一遍现在的图,v点bfs一遍现在的图,确定所有点离这2个点的位置,对于切断的询问更新答案。

    需要注意的就是,每次都一定要重新建图,免得遍历太多的没有用的边。

    递归结束的时候是这幅图只有3个点了,如果在3个点中的最短路,那么一定是1,假定2点不重合。

    代码1:离线写法

    #include<bits/stdc++.h>
    using namespace std;
    #define Fopen freopen("distance.in","r",stdin); freopen("distance.out","w",stdout);
    #define LL long long
    #define ULL unsigned LL
    #define fi first
    #define se second
    #define pb push_back
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define lch(x) tr[x].son[0]
    #define rch(x) tr[x].son[1]
    #define max3(a,b,c) max(a,max(b,c))
    #define min3(a,b,c) min(a,min(b,c))
    typedef pair<int,int> pll;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL mod =  (int)1e9+7;
    const int N = 1e5 + 100;
    struct Node{
        int u, v, id;
    };
    vector<int> vc[N][2], ee[N];
    vector<pll> e[N][2];
    vector<Node> q[N][2];
    int ans[N], pos[N], num[N];
    int lf[N], rt[N], ok[N];
    int d[N][2];
    queue<int> que;
    void bfs(int b, int id){
        d[b][id] = 0;
        que.push(b);
        while(!que.empty()){
            int u = que.front();
            que.pop();
            for(auto v : ee[u]){
                if(d[v][id] > d[u][id]+1){
                    d[v][id] = d[u][id]+1;
                    que.push(v);
                }
            }
        }
    }
    void solve(int k, int op){
        if(vc[k][op].size() <= 3 || q[k][op].size() == 0) return ;
        int nodes = vc[k][op].size();
        for(int i = 0; i < nodes; ++i){
            ee[i].clear();
            pos[vc[k][op][i]] = i;
            d[i][0] = d[i][1] = inf;
            ee[i].pb((i+1)%nodes);
            ee[i].pb((i-1+nodes)%nodes);
        }
        int Max = inf, id = 0;
        for(int i = 0; i < e[k][op].size(); ++i){
            int u = e[k][op][i].fi, v = e[k][op][i].se;
            int tmp = max(pos[v]-pos[u], nodes - pos[v]+pos[u]);
            if(tmp < Max) {
                Max = tmp;
                id = i;
            }
            ee[pos[u]].pb( pos[v]);
            ee[pos[v]].pb( pos[u]);
        }
        vc[k+1][0].clear(); vc[k+1][1].clear();
        q[k+1][1].clear(); q[k+1][0].clear();
        e[k+1][0].clear(); e[k+1][1].clear();
        int tu = e[k][op][id].fi, tv = e[k][op][id].se;
        for(int i = 0; i < nodes; ++i){
            if(vc[k][op][i] == tu || vc[k][op][i] == tv){
                vc[k+1][0].pb(vc[k][op][i]);
                vc[k+1][1].pb(vc[k][op][i]);
            }
            else if(vc[k][op][i] < tu || vc[k][op][i] > tv)
                vc[k+1][0].pb(vc[k][op][i]), lf[vc[k][op][i]] = 1;
            else
                vc[k+1][1].pb(vc[k][op][i]), rt[vc[k][op][i]] = 1;
        }
        bfs(pos[tu], 0);
        bfs(pos[tv], 1);
        for(int i = 0, u, v; i < e[k][op].size(); ++i){
            u = e[k][op][i].fi, v = e[k][op][i].se;
            if(lf[u] || lf[v]) e[k+1][0].pb(e[k][op][i]);
            else if(rt[u] || rt[v]) e[k+1][1].pb(e[k][op][i]);
        }
        for(int i = 0, u, v, aid; i < q[k][op].size(); ++i){
            u = q[k][op][i].u, v = q[k][op][i].v, aid = q[k][op][i].id;
            if(lf[u] && lf[v]) {
                q[k+1][0].pb(q[k][op][i]);
                continue;
            }
            else if(rt[u] && rt[v]){
                q[k+1][1].pb(q[k][op][i]);
                continue;
            }
            u = pos[u], v = pos[v];
            ans[aid] = min(d[u][1]+d[v][1], d[u][0] + d[v][0]);
        }
        for(auto v : vc[k][op]){
            lf[v] = rt[v] = 0;
            ok[v] = 0;
        }
        solve(k+1, 0);
        solve(k+1, 1);
    }
    int main(){
        Fopen;
        int n, m, u, v;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i){
            vc[0][0].pb(i);
        }
        for(int i = 1; i <= n - 3; ++i){
            scanf("%d%d", &u, &v);
            if(u > v) swap(u,v);
            e[0][0].pb({u,v});
        }
        scanf("%d", &m);
        for(int i = 1; i <= m; ++i){
            scanf("%d%d", &u, &v);
            if(u > v) swap(u,v);
            if(u == v)
                continue;
            q[0][0].pb({u,v,i});
        }
        solve(0,0);
        for(int i = 1; i <= m; ++i){
            printf("%d
    ", ans[i]);
        }
        return 0;
    }
    View Code

    离线看着麻烦 其实还是挺简单的。

    代码2:在线写法

    #include<bits/stdc++.h>
    using namespace std;
    #define Fopen freopen("distance.in","r",stdin); freopen("distance.out","w",stdout);
    #define LL long long
    #define ULL unsigned LL
    #define fi first
    #define se second
    #define pb push_back
    #define lch(x) tr[x].son[0]
    #define rch(x) tr[x].son[1]
    #define max3(a,b,c) max(a,max(b,c))
    #define min3(a,b,c) min(a,min(b,c))
    typedef pair<int,int> pll;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL mod =  (int)1e9+7;
    const int N = 5e4+100;
    vector<int> ee[N];
    int pos[N], que[N];
    struct Node{
        vector<int> v, d[2];
        vector<pll> e;
        int mn, mx, nodes;
        Node * lson, * rson;
        void bfs(int b,int id){
            d[id][b] = 0;
            int l = 0, r = 1;
            que[l] = b;
            while(l < r){
                int u = que[l++];
                for(auto v : ee[u]){
                    if(d[id][v] > d[id][u]+1){
                        d[id][v] = d[id][u]+1;
                        que[r++] = v;
                    }
                }
            }
        }
        void solve(){
            nodes = v.size();
            if(nodes <= 3) return ;
            for(int i = 0; i < nodes; ++i){
                pos[v[i]] = i;
                d[0].pb(inf); d[1].pb(inf);
                ee[i].clear();
                ee[i].pb((i+1)%nodes);
                ee[i].pb((i+nodes-1)%nodes);
            }
            int Max = inf, id = 0;
            for(int i = 0; i < nodes-3; ++i){
                int x = pos[e[i].fi], y = pos[e[i].se];
                int tmp = max(y-x, nodes-(y-x));
                if(tmp < Max) {
                    Max = tmp;
                    id = i;
                }
                ee[x].pb(y);
                ee[y].pb(x);
            }
            mn = e[id].fi, mx = e[id].se;
            lson = new Node; rson = new Node;
            for(int i = 0; i < nodes; ++i){
                if(v[i] >= mn && v[i] <= mx) lson -> v.pb(v[i]);
                if(v[i] <= mn || v[i] >= mx) rson -> v.pb(v[i]);
            }
            bfs(pos[mn], 0);
            bfs(pos[mx], 1);
            for(int i = 0; i < nodes-3; ++i){
                int x = e[i].fi, y = e[i].se;
                if((x > mn && x < mx) || (y > mn && y < mx)) lson -> e.pb(e[i]);
                if(x < mn || y < mn || x > mx || y > mx) rson -> e.pb(e[i]);
            }
            lson -> solve();
            rson -> solve();
        }
        int Query(int x, int y){
            if(nodes <= 3) return 1;
            if((x > mn && x < mx) && (y > mn && y < mx)) return lson -> Query(x,y);
            if((x < mn || x > mx) && (y < mn || y > mx)) return rson -> Query(x,y);
            x = lower_bound(v.begin(), v.end(), x) - v.begin();
            y = lower_bound(v.begin(), v.end(), y) - v.begin();
            return min(d[0][x]+d[0][y], d[1][x]+d[1][y]);
        }
    }rt;
    
    int main(){
        Fopen;
        int n, m, u, v;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i){
            rt.v.pb(i);
        }
        for(int i = 1; i <= n - 3; ++i){
            scanf("%d%d", &u, &v);
            if(u > v) swap(u,v);
            rt.e.pb({u,v});
        }
        rt.solve();
        scanf("%d", &m);
        while(m--){
            scanf("%d%d", &u, &v);
            int ans = 0;
            if(u != v) ans = rt.Query(u,v);
            printf("%d
    ", ans);
        }
        return 0;
    }
    View Code

    在线写法要确定询问的点是不是都在一副新的图上,是就继续往下递归,否就在这个地方询问。

    这题目中在线比离线的慢一点点。

    因为在线写法的询问是严格的lg(n)是一个固定值,因为每次往下走,你就会使得二分的长度/2,就相当于是二分了一次了。。。。。

    然后我又写了一个bug,疯狂TLE,惊了。

    int Max = inf, id = 0;
        for(int i = 0; i < e[k][op].size(); ++i){
            int u = e[k][op][i].fi, v = e[k][op][i].se;
            int tmp = max(pos[v]-pos[u], nodes - pos[v]+pos[u]);
            if(tmp < Max) {
               tmp = Max; 
                id = i;
            }
            ee[pos[u]].pb( pos[v]);
            ee[pos[v]].pb( pos[u]);
    }  

    看着没什么问题。。。实际上问题大了。

    应该是 Max = tmp。。。 这样加多了递归的层数,然后会加多存的东西,会导致TLE和MLE。

    #include<bits/stdc++.h>
    using namespace std;
    #define Fopen freopen("distance.in","r",stdin); freopen("distance.out","w",stdout);
    #define LL long long
    #define ULL unsigned LL
    #define fi first
    #define se second
    #define pb push_back
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define lch(x) tr[x].son[0]
    #define rch(x) tr[x].son[1]
    #define max3(a,b,c) max(a,max(b,c))
    #define min3(a,b,c) min(a,min(b,c))
    typedef pair<int,int> pll;
    const int inf = 0x3f3f3f3f;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL mod =  (int)1e9+7;
    const int N = 1e5 + 100;
    struct Node{
        int u, v, id;
    };
    vector<int> vc[N][2], ee[N];
    vector<pll> e[N][2];
    vector<Node> q[N][2];
    int ans[N], pos[N], num[N];
    int lf[N], rt[N], ok[N];
    int d[N][2];
    queue<int> que;
    void bfs(int b, int id){
        d[b][id] = 0;
        que.push(b);
        while(!que.empty()){
            int u = que.front();
            que.pop();
            for(auto v : ee[u]){
                if(ok[v] && d[v][id] > d[u][id]+1){
                    d[v][id] = d[u][id]+1;
                    que.push(v);
                }
            }
        }
    }
    void solve(int k, int op){
        if(vc[k][op].size() <= 3 || q[k][op].size() == 0) return ;
        for(int i = 0; i < vc[k][op].size(); ++i){
            pos[vc[k][op][i]] = i;
            d[vc[k][op][i]][0] = d[vc[k][op][i]][1] = inf;
            ok[vc[k][op][i]] = 1;
        }
        int Max = inf, id = 0, totnum = vc[k][op].size();
        for(int i = 0; i < e[k][op].size(); ++i){
            int u = e[k][op][i].fi, v = e[k][op][i].se;
            int tmp = max(pos[v]-pos[u]-1, totnum - (pos[v]-pos[u]-1) - 2);
            if(tmp < Max) {
                tmp = Max;
                id = i;
            }
        }
        vc[k+1][0].clear(); vc[k+1][1].clear();
        vc[k+1][0].shrink_to_fit(); vc[k+1][1].shrink_to_fit();
        q[k+1][1].clear(); q[k+1][0].clear();
        q[k+1][1].shrink_to_fit(); q[k+1][0].shrink_to_fit();
        e[k+1][0].clear();e[k+1][1].clear();
        e[k+1][0].shrink_to_fit(); e[k+1][1].shrink_to_fit();
        int tu = e[k][op][id].fi, tv = e[k][op][id].se;
        for(int i = 0; i < totnum; ++i){
            if(vc[k][op][i] == tu || vc[k][op][i] == tv){
                vc[k+1][0].pb(vc[k][op][i]);
                vc[k+1][1].pb(vc[k][op][i]);
            }
            else if(vc[k][op][i] < tu || vc[k][op][i] > tv)
                vc[k+1][0].pb(vc[k][op][i]), lf[vc[k][op][i]] = 1;
            else
                vc[k+1][1].pb(vc[k][op][i]), rt[vc[k][op][i]] = 1;
        }
        bfs(tu,0);
        bfs(tv,1);
        for(int i = 0, u, v; i < e[k][op].size(); ++i){
            u = e[k][op][i].fi, v = e[k][op][i].se;
            if(lf[u] || lf[v]) e[k+1][0].pb(e[k][op][i]);
            else if(rt[u] || rt[v]) e[k+1][1].pb(e[k][op][i]);
        }
        for(int i = 0, u, v, aid; i < q[k][op].size(); ++i){
            u = q[k][op][i].u, v = q[k][op][i].v, aid = q[k][op][i].id;
            if(lf[u] && lf[v]) {
                q[k+1][0].pb(q[k][op][i]);
                continue;
            }
            else if(rt[u] && rt[v]){
                q[k+1][1].pb(q[k][op][i]);
                continue;
            }
            ans[aid] = min(ans[aid], d[u][0]+d[v][0]);
            ans[aid] = min(ans[aid], d[u][1]+d[v][1]);
        }
        for(auto v : vc[k][op]){
            lf[v] = rt[v] = 0;
            ok[v] = 0;
        }
        vc[k][op].clear();
        vc[k][op].shrink_to_fit();
        e[k][op].clear();
        e[k][op].shrink_to_fit();
        q[k][op].clear();
        q[k][op].shrink_to_fit();
        solve(k+1, 0);
        solve(k+1, 1);
    }
    int main(){
        Fopen;
        int n, m, u, v;
        scanf("%d", &n);
        for(int i = 1; i < n; ++i){
            vc[0][0].pb(i);
            ee[i].pb(i+1);
            ee[i+1].pb(i);
        }
        vc[0][0].pb(n);
        ee[1].pb(n); ee[n].pb(1);
        for(int i = 1; i <= n - 3; ++i){
            scanf("%d%d", &u, &v);
            if(u > v) swap(u,v);
            e[0][0].pb({u,v});
            ee[u].pb(v);
            ee[v].pb(u);
        }
        scanf("%d", &m);
        memset(ans, inf, sizeof ans);
        for(int i = 1; i <= m; ++i){
            scanf("%d%d", &u, &v);
            if(u > v) swap(u,v);
            if(u == v) {
                ans[i] = 0;
                continue;
            }
            q[0][0].pb({u,v,i});
        }
        solve(0,0);
        for(int i = 1; i <= m; ++i){
            printf("%d
    ", ans[i]);
        }
        return 0;
    }
    View Code

    然后顶着这个破代码 各种乱写 各种MLE, 然后把每一层的东西不需要的那时候马上clear 和 清除空间, 然后就过了。

    然后想改成在线的,改了半天改不动才发现了上面的那个问题。

  • 相关阅读:
    自动化测试随笔4-无法点击底部的完成按钮
    自动化测试随笔3
    自动化测试随笔2
    node.js的Promise库-bluebird示例
    swagger在node.js下的使用
    Angular6基础:在项目中使用less
    Angular最新教程-第三节在谷歌浏览器中调试Angular
    Centos7 设置Mongodb开机启动-自定义服务
    借助 emq 消息服务器搭建微信小程序的mqtt服务器
    linux SFTP用户创建 不允许用户登录,并且连接只允许在制定的目录下进行操作
  • 原文地址:https://www.cnblogs.com/MingSD/p/9995911.html
Copyright © 2011-2022 走看看