zoukankan      html  css  js  c++  java
  • HOJ1127听风

    HOJ1127听风

    该网页无法正常运作

    题面(题面难懂这就是语文题

    一棵根节点为1的树,所有边权均为1,每个节点有不同的颜色C。对这棵树进行游览并统计贡献。

    游览方式

    1. 如果一个节点被游览过就不再游览。
    2. 如果在i号节点,它是叶子节点或者所有儿子都被游览过则停在该节点。
    3. 如果第 i号节点存在儿子没有游览过,则挑选所有未游览的儿子中val[x]最小的一个继续行走。val[x] = min{y|y({in})x的子树}。
      可以任意选择在游览几个节点后结束游览

    每游览一个节点,贡献会加上 这个节点到根节点以及它的子树中颜色的种类 ({-}) 这个节点到根节点的路径长度

    游览结束后,会给很多路径

    贡献会加上max(每条路径上被游览的点数 ({-1}), ({0}))({*})题目提供的权值z

    最终答案为游览结束后的所有可能贡献中的最大值

    原题面不太合适扔在这里 不放了

    这题该咋做

    首先dfs求出游览的顺序,然后树上差分,把最后路径的权值扔到节点上,最后按照游览顺序遍历这颗树,统计当前的总贡献,与答案取max。
    至于节点的颜色,因为数据比较小bitset状态压缩就可以过。
    std给的是dsu on tree,大概学了一学然后滚来更新

    涉及的知识点

    LCA

    LCA模板
    这题我用倍增毕竟Tarjan不会

    树上差分

    其实是第一次写树上差分
    这道题在处理路径的时候使用树上差分。但是给的是路径上节点数-1,该怎么处理呢?
    由于游览顺序已知,我们只要不记录这条路径上最先被游览的节点,就可以保证在计算这条路径时有-1的效果。
    树上差分的标记是打在左右两个节点的,我们只要挑选出这两个中先被游览的点,把标记打在他的父亲即可。

    dsu on tree

    一个好题
    这个就像是在树上进行启发式合并。
    简单的来说,把重儿子子树信息扔到父亲上,轻儿子则扔掉,这样可以保证复杂度({nlog{n}})。(回头写博客吧)这个题还要维护链的信息所以dfs要多记一下信息。

    代码

    这个是bitset的代码,极慢,卡着空间。。。

    #include <iostream>
    #include <cstdio>
    #include <bitset>
    #include <vector>
    #include <queue>
    #include <cmath>
    #include <algorithm>
    #include <ctime>
    namespace fdata
    {
    inline char nextchar()
    {
        static const int BS = 1 << 21;
        static char buf[BS], *st, *ed;
        if (st == ed)
            ed = buf + fread(st = buf, 1, BS, stdin);
        return st == ed ? -1 : *st++;
    }
    template <typename T>
    inline T poread()
    {
        T ret = 0;
        char ch;
        while (!isdigit(ch = nextchar()))
            ;
    
        do
            ret = ret * 10 + ch - '0';
        while (isdigit(ch = nextchar()));
        return ret;
    }
    } // namespace fdata
    using fdata::poread;
    using namespace std;
    const int INF = 1 << 29;
    const int MAXN = 1e5 + 5;
    const int MAXC = 4e3 + 7;
    int n, m, c, t;
    int head[MAXN], ver[MAXN << 1], nxt[MAXN << 1], tot; //邻接表
    inline void add(const int &x, const int &y)
    {
        ver[++tot] = y;
        nxt[tot] = head[x];
        head[x] = tot;
    }
    struct node //记录节点信息
    {
        bitset<MAXC> lian, c;
        vector<int> vct;
        int deep;
        int son;
        int siz;
    } pt[MAXN];
    int dfn[MAXN], cnt;
    int f[MAXN][19]; // lca
    bool cmp(const int &x, const int &y)
    {
        return pt[x].son < pt[y].son;
    }
    void dfs1(int x) //处理子树集合,父亲节点
    {
        pt[x].son = x;
        pt[x].lian |= pt[f[x][0]].lian;
        for (register int i = head[x], y = ver[i]; i; i = nxt[i], y = ver[i])
        {
            if (y == f[x][0])
                continue;
            dfs1(y);
            pt[x].c |= pt[y].c;
            pt[x].son = min(pt[x].son, pt[y].son);
        }
    }
    void dfs2(int x)
    {
        for (register int i = head[x]; i; i = nxt[i])
            if (ver[i] != f[x][0])
                pt[x].vct.push_back(ver[i]);
        sort(pt[x].vct.begin(), pt[x].vct.end(), cmp);
        for (register vector<int>::iterator it = pt[x].vct.begin(); it != pt[x].vct.end(); ++it)
            dfs2(*it);
        dfn[x] = ++cnt;
        pt[x].vct.clear();
    }
    int lca(int x, int y)
    {
        if (pt[x].deep > pt[y].deep)
            swap(x, y);
        int t = (int)(log(n) / log(2)) + 1;
        for (register int i = t; i >= 0; --i)
        {
            if (pt[f[y][i]].deep >= pt[x].deep)
                y = f[y][i];
        }
        if (y == x)
            return x;
        for (register int i = t; i >= 0; --i)
            if (f[x][i] != f[y][i])
                x = f[x][i], y = f[y][i];
        return f[x][0];
    }
    long long Ans = 0;
    long long ans = 0;
    void dfs3(int x)
    {
        for (register int i = head[x]; i; i = nxt[i])
        {
            int y = ver[i];
            if (y == f[x][0])
                continue;
            dfs3(y);
            pt[x].siz += pt[y].siz;
        }
    }
    void dfs4(int x)
    {
        for (register int i = head[x]; i; i = nxt[i])
            if (ver[i] != f[x][0])
                pt[x].vct.push_back(ver[i]);
        sort(pt[x].vct.begin(), pt[x].vct.end(), cmp);
        for (register vector<int>::iterator it = pt[x].vct.begin(); it != pt[x].vct.end(); ++it)
            dfs4(*it);
        ans = (long long)ans + (1ll * pt[x].lian.count() - pt[x].deep + 1) + (1ll * pt[x].siz);
        Ans = max(ans, Ans);
        pt[x].vct.clear();
    }
    inline void bfs()
    {
        queue<int> q;
        q.push(1);
        pt[1].deep = 1;
        f[1][0] = -1;
        while (q.size())
        {
            int x = q.front();
            q.pop();
            for (register int i = head[x], y = ver[i]; i; i = nxt[i], y = ver[i])
            {
                if (pt[y].deep)
                    continue;
                pt[y].deep = pt[x].deep + 1;
                f[y][0] = x;
                for (register int j = 1; j <= t; ++j)
                {
                    f[y][j] = f[f[y][j - 1]][j - 1];
                }
                q.push(y);
            }
        }
        while (q.size())
            q.pop();
    }
    bitset<MAXC> iii;
    signed main()
    {
    #ifdef lky233
        freopen("testdata.in", "r", stdin);
        freopen("testdata.out", "w", stdout);
    #endif
        n = poread<int>(), m = poread<int>(), c = poread<int>();
        t = log(n) / log(2) + 1;
        for (register int i = 1; i <= n; ++i)
            pt[i].lian[poread<int>()] = true, pt[i].c = pt[i].lian;
        for (register int i = 1, x, y; i < n; ++i)
        {
            x = poread<int>(), y = poread<int>();
            add(x, y), add(y, x);
        }
        bfs();
        dfs1(1);
        for (register int i = 1; i <= n; ++i)
            pt[i].lian = pt[i].c | pt[i].lian;
        dfs2(1);
        for (register int i = 1, x, y, z; i <= m; ++i)
        {
            x = poread<int>(), y = poread<int>(), z = poread<int>();
            if (x == y)
                continue;
            if (dfn[x] >= dfn[y])
                swap(x, y);
            x = f[x][0];
            if (x)
                pt[x].siz += z;
            if (y)
                pt[y].siz += z;
            int L = lca(x, y);
            if (L)
                pt[L].siz -= z;
            if (f[L][0])
                pt[f[L][0]].siz -= z;
            // cerr << x << y << L << f[L][0] << endl;
        }
        dfs3(1);
        dfs4(1);
        cerr << "ans: ";
        cerr << Ans << endl;
        cout << Ans << endl;
        cerr << clock() << "ms" << endl;
        return 0;
    }
    

    我回来补上 dsu on tree 了

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <set>
    #include <vector>
    #include <queue>
    #include <cmath>
    #include <algorithm>
    #include <ctime>
    namespace fdata
    {
    inline char nextchar()
    {
        static const int BS = 1 << 21;
        static char buf[BS], *st, *ed;
        if (st == ed)
            ed = buf + fread(st = buf, 1, BS, stdin);
        return st == ed ? -1 : *st++;
    }
    template <typename T>
    inline T poread()
    {
        T ret = 0;
        char ch;
        while (!isdigit(ch = nextchar()))
            ;
    
        do
            ret = ret * 10 + ch - '0';
        while (isdigit(ch = nextchar()));
        return ret;
    }
    } // namespace fdata
    using fdata::poread;
    using namespace std;
    const int MAXN = 1e5 + 5;
    const int MAXC = 4e3 + 5;
    int n, m, c;
    struct Edge
    {
        int ver, nxt;
    } edge[MAXN << 1];
    int head[MAXN], tot;
    inline void add(const int &x, const int &y)
    {
        edge[++tot].ver = y;
        edge[tot].nxt = head[x];
        head[x] = tot;
    }
    struct Point
    {
        vector<int> vct;
        set<int> map;
        int x;
        // 子树大小  重儿子 路径儿子
        int siz, son, rson, deep;
        //节点颜色  子树颜色数    权值
        int color, sumcolor, sum;
    } pt[MAXN];
    int _cnt;
    int dfn[MAXN];
    int cnt[MAXC];
    int rt[MAXN];
    int f[MAXN][19];
    inline bool cmp(const int &x, const int &y)
    {
        return pt[x].rson < pt[y].rson;
    }
    inline bool cmp2(const Point &x, const Point &y)
    {
        return dfn[x.x] < dfn[y.x];
    }
    //一遍bfs预处理求lca
    inline void bfs()
    {
        queue<int> q;
        int t = log(n) / log(2) + 1;
        q.push(1);
        pt[1].deep = 1;
        f[1][0] = 0;
        while (q.size())
        {
            register int x = q.front();
            q.pop();
            for (register int i = head[x], y = edge[i].ver; i; i = edge[i].nxt, y = edge[i].ver)
            {
                if (pt[y].deep)
                    continue;
                pt[y].deep = pt[x].deep + 1;
                f[y][0] = x;
                for (register int j = 1; j <= t; ++j)
                    f[y][j] = f[f[y][j - 1]][j - 1];
                q.push(y);
            }
        }
        while (q.size())
            q.pop();
    }
    inline int lca(const int &X, const int &Y)
    {
        int x = X, y = Y;
        int t = (log(n) / log(2)) + 1;
        if (pt[x].deep > pt[y].deep)
            swap(x, y);
        for (register int i = t; i >= 0; --i)
        {
            if (pt[f[y][i]].deep >= pt[x].deep)
                y = f[y][i];
        }
        if (x == y)
            return x;
        for (register int i = t; i >= 0; --i)
        {
            if (f[x][i] != f[y][i])
                x = f[x][i], y = f[y][i];
        }
        return f[x][0];
    }
    //处理重儿子,路径儿子,子树大小
    void dfs1(int x)
    {
        pt[x].siz = 1;
        pt[x].rson = x;
        for (register int i = head[x], y = edge[i].ver; i; i = edge[i].nxt, y = edge[i].ver)
        {
            if (y == f[x][0])
                continue;
            dfs1(y);
            pt[x].siz += pt[y].siz;
            pt[x].rson = min(pt[x].rson, pt[y].rson);
            if (pt[pt[x].son].siz <= pt[y].siz)
                pt[x].son = y;
        }
    }
    void dfs2(int x)
    {
        for (register int i = head[x], y = edge[i].ver; i; i = edge[i].nxt, y = edge[i].ver)
            if (y != f[x][0])
                pt[x].vct.push_back(y);
        sort(pt[x].vct.begin(), pt[x].vct.end(), cmp);
        for (register vector<int>::iterator it = pt[x].vct.begin(); it != pt[x].vct.end(); ++it)
            dfs2(*it);
        dfn[x] = ++_cnt;
        pt[x].vct.clear();
    }
    void dfs3(int x)
    {
        if (!cnt[pt[x].color])
            ++_cnt;
        cnt[pt[x].color]++;
        for (register int i = head[x], y = edge[i].ver; i; i = edge[i].nxt, y = edge[i].ver)
        {
            if (y == f[x][0])
                continue;
            dfs3(y);
            pt[x].sumcolor += pt[y].sumcolor;
        }
        if (pt[x].son)
            rt[x] = rt[pt[x].son], pt[x].sumcolor = pt[pt[x].son].sumcolor;
        else
            rt[x] = x, pt[x].sumcolor = _cnt;
        for (register int i = head[x], y = edge[i].ver; i; i = edge[i].nxt, y = edge[i].ver)
        {
            if (y == f[x][0] || y == pt[x].son)
                continue;
            y = rt[y];
            for (register set<int>::iterator it = pt[y].map.begin(); it != pt[y].map.end(); ++it)
            {
                register int tmp = *it;
                if (pt[rt[x]].map.find(tmp) == pt[rt[x]].map.end())
                {
                    if (!cnt[tmp])
                        ++pt[x].sumcolor;
                    pt[rt[x]].map.insert(tmp);
                }
            }
            pt[y].map.clear();
        }
        --cnt[pt[x].color];
        if (!cnt[pt[x].color])
            _cnt--;
        pt[rt[x]].map.insert(pt[x].color);
    }
    long long ans = 0, Ans = 0;
    void dfs4(int x)
    {
        for (register int i = head[x], y = edge[i].ver; i; i = edge[i].nxt, y = edge[i].ver)
            if (y != f[x][0])
                pt[x].vct.push_back(y);
        sort(pt[x].vct.begin(), pt[x].vct.end(), cmp);
        for (register vector<int>::iterator it = pt[x].vct.begin(); it != pt[x].vct.end(); ++it)
            dfs4(*it);
        ans = (long long)ans + ((1ll * pt[x].sumcolor) - pt[x].deep + 1) + (1ll * pt[x].sum);
        Ans = max(ans, Ans);
        pt[x].vct.clear();
    }
    void dfs5(int x)
    {
        for (register int i = head[x], y = edge[i].ver; i; i = edge[i].nxt, y = edge[i].ver)
        {
            if (y == f[x][0])
                continue;
            dfs5(y);
            pt[x].sum += pt[y].sum;
        }
    }
    int main()
    {
    #ifdef lky233
        freopen("testdata.in", "r", stdin);
        freopen("testdata.out", "w", stdout);
    #endif
        n = poread<int>(), m = poread<int>(), c = poread<int>();
        for (register int i = 1; i <= n; ++i)
            pt[i].color = poread<int>();
        for (register int i = 1; i <= n; ++i)
            pt[i].x = i;
        for (register int i = 1, x, y; i < n; ++i)
        {
            x = poread<int>(), y = poread<int>();
            add(x, y);
            add(y, x);
        }
        bfs();
        dfs1(1);
        dfs2(1);
        _cnt = 0;
        dfs3(1);
        for (register int i = 1, x, y, z; i <= m; ++i)
        {
            x = poread<int>(), y = poread<int>(), z = poread<int>();
            if (x == y)
                continue;
            if (dfn[x] >= dfn[y])
                swap(x, y);
            x = f[x][0];
            if (x)
                pt[x].sum += z;
            if (y)
                pt[y].sum += z;
            int L = lca(x, y);
            if (L)
                pt[L].sum -= z;
            if (f[L][0])
                pt[f[L][0]].sum -= z;
        }
        dfs5(1);
        dfs4(1);
        cerr << "ans: " << Ans << endl;
        cerr << clock() << "ms" << endl;
        cout << Ans << endl;
    }
    

    坑点

    在树上差分标记的时候,给了一个1-1的路径,这个时候父亲跳到了上面,0有了+3-3-3的标记,1有了+3的标记,查询时导致少了-3,挂掉了。

    大概这样 画的难看

    感谢nofind大佬解释题面,教我树上差分。
    感谢Chrisk大佬指出排版错误,已修正。
    ありがとうございました。

    已完结

    可能指不定哪天回来发个图解释一下做法

  • 相关阅读:
    Hive on Spark
    Mongodb添加副本及修改优先级
    RabbitMQ与Spring集成
    最简单的图文教程,几步完成Git的公私钥配置
    Idea Ant 打开发包
    Spring Web 项目Junit测试报错问题
    阿里云maven仓库地址,速度提升100倍
    Spring boot 学习
    JAVA开发常用工具包
    从无到有搭建SSM框架
  • 原文地址:https://www.cnblogs.com/Shiina-Rikka/p/11541759.html
Copyright © 2011-2022 走看看