• HDU 6039


    建模简析:

    /*
    HDU 6039 - Gear Up [ 建模,线段树,图论 ]  |  2017 Multi-University Training Contest 1
    题意:
    	给你n个齿轮,有些齿轮是同轴的(角速度相同),有些是同边的(线速度相同),任意两个齿轮两种关系中至多只有一种,且任意两个齿轮之间只有一条路径
    	给出所有齿轮的半径和 m组两两之间的关系
    	两种操作:1. 把改变某个齿轮的半径; 2. 赋予某个齿轮一个角速度,问所有齿轮中最大的角速度是多少
    分析:
    	相邻齿轮连边建图,原图是森林,按单棵树考虑。
    	由于同轴的齿轮在角速度上相同,故可缩点成齿轮组,新图上各组齿轮同边,且任意两个齿轮组只有一对齿轮同边
    	单棵树上的齿轮在角速度上有着倍数关系,故可以以某一个齿轮为参照,维护别的齿轮和它在角速度上的倍数
    	可以想象,以根节点为参照,齿轮组 u 对于根节点的角速度的倍数与其直接相邻的齿轮 f 的关系 Ku = Kf * Rf / Ru
    	当某个齿轮半径改变后,相当于区间修改子树的倍数,查询则是查询该齿轮所在树的最大值
    	大体看得出线段树模型,根据dfs序维护,但是乘法不易维护,则将上表达式取对数:log2(Ku) = log2(Kf) + log2(Rf) - log2(Ru)
    	维护对数则只需维护加减法,由于题中半径均为2的幂次,故对数取以二为底
    	
    	查询操作容易写,修改操作需分类讨论
    	1.该齿轮是直接与上一个齿轮组同边的齿轮
    		该齿轮变大,同轴所有齿轮角速度变慢,与该齿轮直接同边的子树上的齿轮组不受影响,反之亦然
    	2.该齿轮不是直接与上一个齿轮组同边的齿轮
    		该齿轮变大,同轴所有齿轮角速度不受影响,与该齿轮直接同边的子树上的齿轮组变快,反之亦然
    
    	具体操作时,维护两个dfs序,一个是同轴齿轮组的整棵子树的dfs序,另一个是与该齿轮直接同边的子树dfs序
    	维护后一个dfs序时,可对于每一个节点,把这个节点所有连接的点排序,使得和该点同边的点在对应 vector 中的前缀里(就不用缩点了)
    
    编码时长:8小时(-INF)
    */
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 100005;
    const int INF = 0x3f3f3f3f;
    double ln2 = log(2.);
    struct Edge{
        int v, type;
    };
    bool cmp(Edge a, Edge b) {
        return a.type > b.type;
    }
    vector<Edge> edge[N];
    int rad[N], rate[N], f[N], rt[N];
    int l[N], r[N], ll[N], rr[N], pos, p[N];
    int n, m, q;
    void init(){
        for (int i = 0; i < N; i++) {
            edge[i].clear();
            ll[i] = INF;
            l[i] = r[i] = rr[i] = 0;
            f[i] = 0;
        }
        pos = 0;
    }
    void dfs(int u, int pre)
    {
        sort(edge[u].begin(), edge[u].end(), cmp);
        rt[u] = rt[pre];
        l[u] = ++pos;
        p[pos] = u;
        for (const auto& e : edge[u])
        {
            if (e.v == pre) continue;
            if (e.type == 1) {
                rate[e.v] = rad[u] - rad[e.v] + rate[u];
                f[e.v] = e.v;
                ll[u] = min(ll[u], pos+1);
                dfs(e.v, u);
                rr[u] = max(rr[u], pos);
            } else {
                rate[e.v] = rate[u];
                f[e.v] = f[u];
                dfs(e.v, u);
            }
        }
        r[u] = pos;
    }
    int Max[N<<2], add[N<<2];
    void Up(int x) {
        Max[x] = max(Max[x<<1], Max[x<<1|1]);
    }
    void Down(int x) {
        if (add[x]) {
            Max[x<<1] += add[x];
            Max[x<<1|1] += add[x];
            add[x<<1] += add[x];
            add[x<<1|1] += add[x];
            add[x] = 0;
        }
    }
    void Build(int l, int r, int x) {
        add[x] = 0;
        if (l == r) {
            Max[x] = rate[p[l]]; return;
        }
        int mid = (l+r) >> 1;
        Build(l, mid, x<<1); Build(mid+1, r, x<<1|1);
        Up(x);
    }
    void Change(int L, int R, int num, int l, int r, int x) {
        if (L <= l && r <= R) {
            add[x] += num; Max[x] += num;
            return;
        }
        Down(x);
        int mid = (l + r) >> 1;
        if (L <= mid) Change(L, R, num, l, mid, x<<1);
        if (mid < R) Change(L, R, num, mid+1, r, x<<1|1);
        Up(x);
    }
    int Query(int L, int R, int l, int r, int x) {
        if (L <= l && r <= R) return Max[x];
        Down(x);
        int mid = (l+r) >> 1;
        int res = -INF;
        if (L <= mid) res = max(res, Query(L, R, l, mid, x<<1));
        if (R > mid) res = max(res, Query(L, R, mid+1, r, x<<1|1));
        return res;
    }
    int main()
    {
        int tt = 0, i, a, x, y;
        while (~scanf("%d%d%d", &n, &m, &q))
        {
            init();
            for (i = 1; i <= n; i++)
            {
                scanf("%d", &rad[i]);
                rad[i] = log2(rad[i]);
            }
            for (i = 1; i <= m; i++)
            {
                scanf("%d%d%d", &a, &x, &y);
                edge[x].push_back(Edge{y, a});
                edge[y].push_back(Edge{x, a});
            }
            for (i = 1; i <= n; i++)
                if (!f[i]) {
                    rt[i] = f[i] = i;
                    rate[i] = 0;
                    dfs(i, i);
            }
            Build(1, n, 1);
            printf("Case #%d:
    ", ++tt);
            while (q--)
            {
                scanf("%d%d%d", &a, &x, &y);
                if (a == 1)
                {
                    y = log2(y);
                    if (f[x] == x && rt[x] != x) Change(l[x], r[x], rad[x]-y, 1, n, 1);
                    if (ll[x] <= rr[x]) Change(ll[x], rr[x], y-rad[x], 1, n, 1);
                    rad[x] = y;
                }
                else
                {
                    int km = Query(l[rt[x]], r[rt[x]], 1, n, 1);
                    int k = Query(l[x], l[x], 1, n, 1);
                    double au = log2(y) + km - k;
                    printf("%.3f
    ", au*ln2);
                }
            }
        }
    }
    

      

    按标程的思路,不同的主要是缩点:

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 100005;
    const int INF = 0x3f3f3f3f;
    double ln2 = log(2.);
    int f[N];
    int sf(int x) {
        return x == f[x] ? x : f[x] = sf(f[x]);
    }
    struct Edge{ int v, w, dis; };
    vector<int> edge[N];
    vector<Edge> lnk[N];
    int rad[N], rt[N], rate[N], up[N];
    int l[N], r[N], ll[N], rr[N], pos;
    int n, m, q;
    void init()
    {
        for (int i = 0; i < N; i++)
        {
            f[i] = i;
            edge[i].clear();
            lnk[i].clear();
            l[i] = r[i] = 0;
            ll[i] = INF;
            rt[i] = up[i]= rr[i] = 0;
        }
        pos = 0;
    }
    void dfs(int u, int pre, int root, int dis)
    {
        rt[u] = root;
        l[u] = ++pos;
        rate[l[u]] = dis;
        for (const auto &e: lnk[u])
        {
            if (pre == e.v) {
                up[e.w] = 1;
            } else {
                ll[e.w] = min(ll[e.w], pos+1);
                dfs(e.v, u, root, dis+e.dis);
                rr[e.w] = max(rr[e.w], pos);
            }
        }
        r[u] = pos;
    }
    int Max[N<<2], add[N<<2];
    void Up(int x) {
        Max[x] = max(Max[x<<1], Max[x<<1|1]);
    }
    void Down(int x) {
        if (add[x]) {
            Max[x<<1] += add[x];
            Max[x<<1|1] += add[x];
            add[x<<1] += add[x];
            add[x<<1|1] += add[x];
            add[x] = 0;
        }
    }
    void Build(int l, int r, int x) {
        add[x] = 0;
        if (l == r) {
            Max[x] = rate[l]; return;
        }
        int mid = (l+r) >> 1;
        Build(l, mid, x<<1); Build(mid+1, r, x<<1|1);
        Up(x);
    }
    void Change(int L, int R, int num, int l, int r, int x) {
        if (L <= l && r <= R) {
            add[x] += num; Max[x] += num;
            return;
        }
        Down(x);
        int mid = (l + r) >> 1;
        if (L <= mid) Change(L, R, num, l, mid, x<<1);
        if (mid < R) Change(L, R, num, mid+1, r, x<<1|1);
        Up(x);
    }
    int Query(int L, int R, int l, int r, int x) {
        if (L == 0 || R == 0) return 0;
        if (L <= l && r <= R) return Max[x];
        Down(x);
        int mid = (l+r) >> 1;
        int res = -INF;
        if (L <= mid) res = max(res, Query(L, R, l, mid, x<<1));
        if (R > mid) res = max(res, Query(L, R, mid+1, r, x<<1|1));
        return res;
    }
    int main()
    {
        int tt = 0, i, a, x, y;
        while (~scanf("%d%d%d", &n, &m, &q))
        {
            init();
            for (i = 1; i <= n; i++)
            {
                scanf("%d", &rad[i]);
                rad[i] = log2(rad[i]);
            }
            for (i = 1; i <= m; i++)
            {
                scanf("%d%d%d", &a, &x, &y);
                if (a == 1)
                {
                    edge[x].push_back(y);
                    edge[y].push_back(x);
                }
                else f[sf(x)] = sf(y);
            }
            for (i = 1; i <= n; i++)
                for (auto& x: edge[i])
                    lnk[sf(i)].push_back(Edge{sf(x), i, rad[i] - rad[x]});
            for (i = 1; i <= n; i++)
                if (sf(i) == i && !rt[i])
                    dfs(i, i, i, 0);
            Build(1, pos, 1);
            printf("Case #%d:
    ", ++tt);
            while (q--)
            {
                scanf("%d%d%d", &a, &x, &y);
                if (a == 1)
                {
                    y = log2(y);
                    int fx = sf(x);
                    if (up[x]) Change(l[fx], r[fx], rad[x]-y, 1, pos, 1);
                    if (ll[x] <= rr[x]) Change(ll[x], rr[x], y-rad[x], 1, pos, 1);
                    rad[x] = y;
                } else {
                    x = sf(x);
                    int km = Query(l[rt[x]], r[rt[x]], 1, pos, 1);
                    int k = Query(l[x], l[x], 1, pos, 1);
                    double au = log2(y) + km - k;
                    printf("%.3f
    ", au*ln2);
                }
            }
        }
    }
    

      

    我自倾杯,君且随意
  • 相关阅读:
    [HDU 1003] Max Sum
    Codeforces
    2016 年宁波工程学院第七届ACM校赛题解报告
    [DP] Light Oj 1017 Brush(III)
    GDUT-校赛-积水积木
    1031 Hungar的得分问题(二)
    HDU 1506 Largest Rectangle in a Histogram
    lightoj 1033 Generating Palindromes
    网络编程总结
    生产者消费者模型
  • 原文地址:https://www.cnblogs.com/nicetomeetu/p/7258097.html
Copyright © 2020-2023  润新知