2021年第46屆ICPC亞洲區域賽(濟南站)A


題意

現在有一棵在三維空間中的樹,樹上每條邊一定是某個坐標軸(x/y/z)正/反方向的向量。

現在有兩類操作。

旋轉操作:u v axis degree。(axis=x/y/z,degree=90/180/270。 表示將邊(u,v)以從u出發向axis的正方向向量為軸,旋轉degree度。)

詢問操作:u v。你需要回答u,v之間的歐式距離。

n,Q <= 1e5

題解

旋轉操作類型可以看作空間向量的繞軸旋轉(此處向量為父節點指向子節點的空間向量)

其中R就是三階的旋轉矩陣。繞X、Y、Z軸旋轉(右手螺旋規則)的變換矩陣為

建立根節點值為向量(0, 0, 0)其余結點值為父節點指向該節點的向量的有根樹,dfs序輕重鏈剖分該樹。用線段樹維護樹鏈的向量和,則維護了u相對於v的向量,該向量的模即為u、v間的歐幾里得距離,那么可以在時間復雜度完成操作2。用線段樹懶標記維護區間操作,從而實現子樹的乘法以及單點乘法,可以在復雜度下完成操作1,注意操作1涉及兩種不同的操作,一類是“父親固定,旋轉兒子”,對應兒子所在子樹的區間乘,另一類是“兒子固定,父親旋轉”,對應兒子所在子樹的區間乘 + 兒子單點乘 + 整棵樹的區間乘。

具體實現如下。

(這場比賽拿了個金,還不錯。

代碼

 

#include <bits/stdc++.h>
#define IOS std::cin.tie(nullptr)->sync_with_stdio(false);
using namespace std;
using ll = __int128_t;
using FLOAT_ = long double;

template <typename T, int maxn> 
class matrix {
private:

    int n;
    T a[maxn+1][maxn+1];

public:

    explicit matrix(int n = 3) : n(n) { clear(); }

    matrix(const initializer_list<initializer_list<T>>& lst) {
        this->n = lst.size();
        int i = 1;
        for(auto it = lst.begin();it != lst.end();++it, ++i) {
            int j = 1;
            for(auto it2 = it->begin();it2 != it->end();++it2, ++j) {
                a[i][j] = *it2;
            }
        }
    }

    void resize(int n) { this->n = n; clear(); }

    void clear() {
        for(int i = 1;i <= n;++i) {
            for(int j = 1;j <= n;++j) {
                a[i][j] = 0;
            }
        }
    }

    // res = m1 * m2
    friend matrix operator*(const matrix& m1, const matrix& m2) {
        assert(m1.n == m2.n);
        int n = m1.n;
        matrix res(n);
        for(int i = 1;i <= n;++i) {
            for(int j = 1;j <= n;++j) {
                for(int k = 1;k <= n;++k) {
                    res.a[i][j] += m1.a[i][k] * m2.a[k][j];
                }
            }
        }
        return res;
    }

    matrix<T, maxn>& operator=(const matrix<T, maxn>& oth) {
        n = oth.n;
        for(int i = 1;i <= n;++i) {
            for(int j = 1;j <= n;++j) {
                a[i][j] = oth.a[i][j];
            }
        }
        return *this;
    }

    matrix<T, maxn> operator+(const matrix<T, maxn>& oth) const {
        assert(n == oth.n);
        matrix<T, maxn> res(n);
        for(int i = 1;i <= n;++i) {
            for(int j = 1;j <= n;++j) {
                res.a[i][j] = a[i][j] + oth.a[i][j];
            }
        }
        return res;
    }

    matrix<T, maxn> operator-() const {
        matrix<T, maxn> res(n);
        for(int i = 1;i <= n;++i) {
            for(int j = 1;j <= n;++j) {
                res.a[i][j] = -a[i][j];
            }
        }
        return res;
    }

    matrix<T, maxn> operator-(const matrix<T, maxn>& oth) const {
        return (*this) + (-oth);
    }

    bool operator==(const matrix<T, maxn>& oth) const {
        if(n != oth.n) { return false; }
        for(int i = 1;i <= n;++i) {
            for(int j = 1;j <= n;++j) {
                if(a[i][j] != oth.a[i][j]) { return false; }
            }
        }
        return true;
    }

    bool operator!=(const matrix<T, maxn>& oth) const {
        return !(*this == oth);
    }

    int size() const { return n; }

    T* operator[](int x) { return a[x]; }
    const T* operator[](int x) const { return a[x]; }

    T& X() { return a[1][1]; }

    T& Y() { return a[2][1]; }

    T& Z() { return a[3][1]; }

    T X() const { return a[1][1]; }
    
    T Y() const { return a[2][1]; }

    T Z() const { return a[3][1]; }

    FLOAT_ get_dis() const {
        return sqrt((FLOAT_)(X() * X() + Y() * Y() + Z() * Z()));
    }

    string to_string() const {
        string res = "matrix{\n";
        for(int i = 1;i <= n;++i) {
            res += "{";
            for(int j = 1;j <= n;++j) {
                res += std::to_string(a[i][j]);
                if(j < n) {
                    res += ", ";
                }
            }
            res += "}";
            if(i < n) {
                res += ", ";
            }
            res += "\n";
        }
        res += "}\n";
        return res;
    }

};

using Vector3 = matrix<ll, 3>;

const matrix<ll, 3> I = {
    {1, 0, 0},
    {0, 1, 0},
    {0, 0, 1}
};

const matrix<ll, 3> rx90 = {
    {1, 0, 0},
    {0, 0, -1},
    {0, 1, 0}
};

const matrix<ll, 3> rx180 = {
    {1, 0, 0},
    {0, -1, 0},
    {0, 0, -1}
};

const matrix<ll, 3> rx270 = {
    {1, 0, 0},
    {0, 0, 1},
    {0, -1, 0}
};

const matrix<ll, 3> ry90 = {
    {0, 0, 1},
    {0, 1, 0},
    {-1, 0, 0}
};

const matrix<ll, 3> ry180 = {
    {-1, 0, 0},
    {0, 1, 0},
    {0, 0, -1}
};

const matrix<ll, 3> ry270 = {
    {0, 0, -1},
    {0, 1, 0},
    {1, 0, 0}
};

const matrix<ll, 3> rz90 = {
    {0, -1, 0},
    {1, 0, 0},
    {0, 0, 1}
};

const matrix<ll, 3> rz180 = {
    {-1, 0, 0},
    {0, -1, 0},
    {0, 0, 1}
};

const matrix<ll, 3> rz270 = {
    {0, 1, 0},
    {-1, 0, 0},
    {0, 0, 1}
};

inline void getVector3(Vector3& dst, const string& axis, int w) {
    dst.clear();
    if(axis.back() == '-') { w = -w; }
    if(axis.front() == 'x') {
        dst.X() += w;
    } else if(axis.front() == 'y') {
        dst.Y() += w;
    } else {
        dst.Z() += w;
    }
}

const int maxn = 1e5 + 50;

int n, q;

struct edge_node {
    int to, nxt;
    int w;
    string axis;
} edge[maxn<<1];

int head[maxn], id = 2;

inline void add_edge(int u, int v, int w, const string& axis) {
    edge[id] = edge_node {v, head[u], w, axis};
    head[u] = id++;
    string axis_r = axis.back() == '+' ? axis.front() + string("-") : axis.front() + string("+");
    edge[id] = edge_node {u, head[v], w, axis_r};
    head[v] = id++;
}

Vector3 wi[maxn];

int dfn[maxn], cnt = 0, depth[maxn], sz[maxn], top[maxn], fa[maxn], son[maxn];
Vector3 dfnw[maxn];

void dfs1(int u, int pre) {
    depth[u] = depth[pre] + 1;
    sz[u] = 1;
    fa[u] = pre;
    for(int i = head[u]; i;i = edge[i].nxt) {
        int v = edge[i].to;
        if(v != pre) {
            getVector3(wi[v], edge[i].axis, edge[i].w);
            dfs1(v, u);
            sz[u] += sz[v];
            if(sz[son[u]] < sz[v]) {
                son[u] = v;
            }
        }
    }
}

void dfs2(int u, int t) {
    dfn[u] = ++cnt;
    dfnw[cnt] = wi[u];
    top[u] = t;
    if(!son[u]) return;
    dfs2(son[u], t);
    for(int i = head[u]; i;i = edge[i].nxt) {
        int v = edge[i].to;
        if(v != fa[u] && v != son[u]) {
            dfs2(v, v);
        }
    }
}

#define lson (rt<<1)
#define rson (rt<<1|1)
#define mid  (l+((r-l)>>1))

struct ty {
    Vector3 sum;
    Vector3 mul;
} tree[maxn<<2];

inline void push_up(int rt) {
    auto& res = tree[rt];
    auto& lres = tree[lson];
    auto& rres = tree[rson];
    res.sum = lres.sum + rres.sum;
}

void build(int rt, int l, int r) {
    tree[rt].mul = I;
    if(l == r) {
        tree[rt].sum = dfnw[l];
        return;
    }
    build(lson, l, mid);
    build(rson, mid + 1, r);
    push_up(rt);
}

inline void push_mul(int rt, const Vector3& mul) {
    tree[rt].sum = mul * tree[rt].sum;
    tree[rt].mul = mul * tree[rt].mul;
}

inline void push_down(int rt) {
    if(tree[rt].mul != I) {
        const auto& mul = tree[rt].mul;

        push_mul(lson, mul);
        push_mul(rson, mul);

        tree[rt].mul = I;
    }
}

void mul(int rt, int l, int r, int x, int y, const Vector3& val) {
    if(x == l && r == y) {
        push_mul(rt, val);
        return;
    }
    push_down(rt);
    if(y <= mid) {
        mul(lson, l, mid, x, y, val);
    } else if(x > mid) {
        mul(rson, mid + 1, r, x, y, val);
    } else {
        mul(lson, l, mid, x, mid, val);
        mul(rson, mid + 1, r, mid + 1, y, val);
    }
    push_up(rt);
}

Vector3 query(int rt, int l, int r, int x, int y) {
    if(x == l && r == y) {
        return tree[rt].sum;
    }
    push_down(rt);
    if(y <= mid) {
        return query(lson, l, mid, x, y);
    } else if(x > mid) {
        return query(rson, mid + 1, r, x, y);
    }
    auto lres = query(lson, l, mid, x, mid);
    auto rres = query(rson, mid + 1, r, mid + 1, y);
    return lres + rres;
}

#undef lson
#undef rson
#undef mid

void mul_tree(int u, const Vector3& val) {
    mul(1, 1, n, dfn[u], dfn[u] + sz[u] - 1, val);
}

void mul_vertex(int u, const Vector3& val) {
    mul(1, 1, n, dfn[u], dfn[u], val);
}

FLOAT_ query_path(int u, int v) {
    Vector3 udis, vdis, dis;

    while(top[u] != top[v]) {
        if(depth[top[u]] >= depth[top[v]]) {
            udis = udis + query(1, 1, n, dfn[top[u]], dfn[u]);
            u = fa[top[u]];
        } else {
            vdis = vdis + query(1, 1, n, dfn[top[v]], dfn[v]);
            v = fa[top[v]];
        }
    }

    if(depth[u] >= depth[v]) {
        udis = udis + query(1, 1, n, dfn[v], dfn[u]);
        auto lca_dis = query(1, 1, n, dfn[v], dfn[v]);
        dis = udis - lca_dis - vdis; 
    } else {
        vdis = vdis + query(1, 1, n, dfn[u], dfn[v]);
        auto lca_dis = query(1, 1, n, dfn[u], dfn[u]);
        dis = vdis - lca_dis - udis;
    }

    return dis.get_dis();
}

signed main() {
    IOS
    cin >> n >> q;
    for(int i = 1;i <= n - 1;++i) {
        int u, v, w;
        string axis;
        cin >> u >> v >> w >> axis;
        add_edge(u, v, w, axis);
    }
    dfs1(1, 0);
    dfs2(1, 1);
    build(1, 1, n);
    while(q--) {
        int op;
        cin >> op;
        if(op == 1) {
            int u, v;
            char axis;
            int deg;
            cin >> u >> v >> axis >> deg;
            if(axis == 'x') {
                if(fa[v] == u) {
                    if(deg == 90) {
                        mul_tree(v, rx90);
                    } else if(deg == 180) {
                        mul_tree(v, rx180);
                    } else {
                        mul_tree(v, rx270);
                    }
                } else {
                    if(deg == 90) {
                        mul_tree(u, rx270);
                        mul_vertex(u, rx90);
                        mul_tree(1, rx90);
                    } else if(deg == 180) {
                        mul_tree(u, rx180);
                        mul_vertex(u, rx180);
                        mul_tree(1, rx180);
                    } else {
                        mul_tree(u, rx90);
                        mul_vertex(u, rx270);
                        mul_tree(1, rx270);
                    }
                }
            }
            if(axis == 'y') {
              if(fa[v] == u) {
                    if(deg == 90) {
                        mul_tree(v, ry90);
                    } else if(deg == 180) {
                        mul_tree(v, ry180);
                    } else {
                        mul_tree(v, ry270);
                    }
                } else {
                    if(deg == 90) {
                        mul_tree(u, ry270);
                        mul_vertex(u, ry90);
                        mul_tree(1, ry90);
                    } else if(deg == 180) {
                        mul_tree(u, ry180);
                        mul_vertex(u, ry180);
                        mul_tree(1, ry180);
                    } else {
                        mul_tree(u, ry90);
                        mul_vertex(u, ry270);
                        mul_tree(1, ry270);
                    }
                }
            }
            if(axis == 'z') {
                if(fa[v] == u) {
                    if(deg == 90) {
                        mul_tree(v, rz90);
                    } else if(deg == 180) {
                        mul_tree(v, rz180);
                    } else {
                        mul_tree(v, rz270);
                    }
                } else {
                    if(deg == 90) {
                        mul_tree(u, rz270);
                        mul_vertex(u, rz90);
                        mul_tree(1, rz90);
                    } else if(deg == 180) {
                        mul_tree(u, rz180);
                        mul_vertex(u, rz180);
                        mul_tree(1, rz180);
                    } else {
                        mul_tree(u, rz90);
                        mul_vertex(u, rz270);
                        mul_tree(1, rz270);
                    }
                }
            }
        } else {
            int u, v;
            cin >> u >> v;
            auto res = query_path(u, v);
            cout << fixed << setprecision(15) << res << '\n';
        }
    }
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM