zoukankan      html  css  js  c++  java
  • Luogu 3320 [SDOI2015]寻宝游戏

    一开始还真没想到。

    发现从所有有宝藏的点出发绕一圈只要不刻意绕路答案都是一样的,即我们呢要求的最后答案$ans = dis(x_1, x_2) + dis(x_2, x_3) +... + dis(x_{k - 1}, x_k) + dis(x_k, x_1)$。

    不刻意绕远路怎么办呢,我们把有宝藏的点按照$dfs$序,维护一个有序的$set$就可以了。

    每次插入就相当于找到一个点$x$在$dfs$序中的前一个点$lst$和后一个点$nxt$,使最后的答案减去$dis(nxt, lst)$并加上$dis(x, nxt) + dis(lst, x)$,删除同理。

    我选择用倍增来求$dis(x, y)$。

    $set$的细节一开始没想清楚,写了一会儿。

    时间复杂度$O(nlogn)$。

    Code:

    #include <cstdio>
    #include <cstring>
    #include <set>
    using namespace std;
    typedef long long ll;
    
    const int N = 1e5 + 5;
    const int Lg = 20;
    
    int n, qn, tot = 0, head[N];
    int dep[N], fa[N][Lg], dfsc = 0, id[N], mp[N];
    ll ans = 0LL, dis[N];
    bool ex[N];
    set <int> s;
    
    struct Edge {
        int to, nxt;
        ll val;
    } e[N << 1];
    
    inline void add(int from, int to, ll val) {
        e[++tot].to = to;
        e[tot].val = val;
        e[tot].nxt = head[from];
        head[from] = tot;
    }  
    
    template <typename T>
    inline void read(T &X) {
        X = 0; char ch = 0; T op = 1;
        for(; ch > '9' || ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
    
    void dfs(int x, int fat, int depth, ll nowDis) {
        fa[x][0] = fat, dep[x] = depth, dis[x] = nowDis;
        id[x] = ++dfsc, mp[id[x]] = x;
        for(int i = 1; i <= 18; i++)
            fa[x][i] = fa[fa[x][i - 1]][i - 1];
        for(int i = head[x]; i; i = e[i].nxt) {
            int y = e[i].to;
            if(y == fat) continue;
            dfs(y, x, depth + 1, nowDis + e[i].val);
        }
    }
    
    inline void swap(int &x, int &y) {
        int t = x; x = y; y = t;
    }
    
    inline int getLca(int x, int y) {
        if(dep[x] < dep[y]) swap(x, y);
        for(int i = 18; i >= 0; i--)
            if(dep[fa[x][i]] >= dep[y])
                x = fa[x][i];
        if(x == y) return x;
        for(int i = 18; i >= 0; i--)
            if(fa[x][i] != fa[y][i])
                x = fa[x][i], y = fa[y][i];
        return fa[x][0];
    }
    
    inline ll getDis(int x, int y) {
        int z = getLca(x, y);
        return dis[x] + dis[y] - 2 * dis[z];
    }
    
    int main() {
        read(n), read(qn);
        for(int x, y, i = 1; i < n; i++) {
            read(x), read(y);
            ll v; read(v);
            add(x, y, v), add(y, x, v); 
        }
        dfs(1, 0, 1, 0LL);
        
    /*    for(int i = 1; i <= n; i++) 
            printf("%d ", id[i]);
        printf("
    ");    */
        
        for(int x, cnt = 0; qn--; ) {
            read(x);
            if(!ex[x]) {
                ex[x] = 1;
                s.insert(id[x]);
                ++cnt;
                if(cnt == 1) {
                    puts("0");
                    continue;
                }
                set <int> :: iterator it = s.find(id[x]), it2 = it;
                if(it == s.begin()) it = s.end();
                int lst = *(--it);
                it = s.find(id[x]);
                int nxt = 0;
                if((++it2) == s.end()) nxt = *(s.begin());
                else nxt = *(++it);
                ans += getDis(mp[lst], x) + getDis(mp[nxt], x) - getDis(mp[lst], mp[nxt]);
            } else {
                ex[x] = 0;
                --cnt;
                if(cnt == 0) {
                    puts("0");
                    s.erase(id[x]);
                    continue;
                }
                set <int> :: iterator it = s.find(id[x]), it2 = it;
                if(it == s.begin()) it = s.end();
                int lst = *(--it);
                it = s.find(id[x]);
                int nxt = 0;
                if((++it2) == s.end()) nxt = *(s.begin());
                else nxt = *(++it);
                ans -= getDis(mp[lst], x) + getDis(mp[nxt], x) - getDis(mp[lst], mp[nxt]);            
                s.erase(id[x]);
            }
            printf("%lld
    ", ans);
        }
        
        return 0;
    }
    View Code
  • 相关阅读:
    Douglas-Peucker 轨迹压缩算法
    Marching squares 算法 获取轮廓(contour tracing)
    创建Mesh->格子地图转NavMesh->可破坏墙壁
    StretchedBillboard 实现
    程序员的微创业
    买云服务器有推荐吗?国内知道有腾讯云、阿里云...等等,不知道该选哪个好了,另外优惠吗?
    我的阿里云5年
    2021阿里云、腾讯云、华为云、滴滴云评测比较
    终于找到可以一文多发的平台了!
    2019年最新阿里云主机优惠购买指南
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9682792.html
Copyright © 2011-2022 走看看