• bzoj 1023: [SHOI2008]cactus仙人掌图


        这道题是我做的第一道仙人掌DP,小小纪念一下……

        仙人掌DP就是环上的点环状DP,树上的点树上DP。就是说,做一遍DFS,DFS的过程中处理出环,环上的点先不DP,先把这些换上的点的后继点都处理出来,再从环上DFS序最小的点开始进行环状DP,就ok了。但是注意判断是不是父边不能用 v[k] != fa[now],这样如果两个点构成一个环就会出错,所以存这个点的父边,记为fb[now],这样判断的时候只需判断(k^1) != fb[now],就可以了。在环状DP的时候我想了很久怎么用单调队列优化(其实是我太弱了,环状DP都不会写=_=)。存一个p[i] = f[i]-i,然后用 f[i]+i+p[j] 更新答案就可以了,最后只需更新环最顶端的点的 f 值而不用全部修改。

        这么说很笼统,还是看代码:

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <stack>
    #define N 500100
    #define M 1001000
    using namespace std;
     
    int n, m;
    int p[N], next[M], v[M], bnum = -1;
    int f[N] = {0};
    int ans = 0;
     
    void addbian(int x, int y)
    {
        bnum++; next[bnum] = p[x]; p[x] = bnum; v[bnum] = y;
        bnum++; next[bnum] = p[y]; p[y] = bnum; v[bnum] = x;
    }
     
    int nowtime = 0;
    int low[N], vist[N] = {0}, fb[N], fa[N];
    bool instack[N] = {0};
     
    int roop[N], roopnum;
     
    struct ss
    {
        int place, val;
    }dui[N];
    int head, tail;
     
    void work_circle()
    {
        int limit = roopnum/2;
        for (int i = roopnum+1; i <= (roopnum<<1); ++i) roop[i] = roop[i-roopnum];
        ss x; x.val = f[roop[1]]-1; x.place = 1;
        head = 1; tail = 1; dui[head] = x;
        for (int i = 2; i <= (roopnum<<1); ++i)
        {
            while (dui[head].place+limit < i) head++;
            ans = max(ans, f[roop[i]]+i+dui[head].val);
            x.val = f[roop[i]]-i; x.place = i;
            while (dui[tail].val < x.val && tail >= head) tail--;
            dui[++tail] = x;
        }
    }
     
    void dfs(int now)
    {
        int k = p[now]; vist[now] = ++nowtime; low[now] = vist[now];
        while (k != -1)
        {
            if (k != fb[now])
            {
                if (vist[v[k]]) low[now] = min(low[now], vist[v[k]]);
                else
                {
                    fa[v[k]] = now; fb[v[k]] = k^1;
                    dfs(v[k]);
                    low[now] = min(low[now], low[v[k]]);
                }
            }
            k = next[k];
        }
        k = p[now];
        while (k != -1)
        {
            if ((k^1) == fb[v[k]] && low[v[k]] > vist[now])
            {
                ans = max(ans, f[now] + f[v[k]] + 1);
                f[now] = max(f[now], f[v[k]] + 1);
            }
            if ((k^1) != fb[v[k]] && vist[now] < vist[v[k]])
            {
                roopnum = 0;
                int x = v[k];
                while (x != fa[now])
                {
                    roop[++roopnum] = x;
                    x = fa[x];
                }
                work_circle();
                for (int i = 1; i < roopnum; ++i)
                    f[now] = max(f[now], f[roop[i]]+min(i, roopnum-i));
            }
            k = next[k];
        }
    }
     
    int main()
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; ++i) p[i] = -1;
        for (int i = 1; i <= m; ++i)
        {
            int k, x, y; scanf("%d%d", &k, &x);
            for (int j = 1; j < k; ++j)
            {
                scanf("%d", &y);
                addbian(x, y);
                x = y;
            }
        }
        fa[1] = 0; fb[1] = -1; dfs(1);
        printf("%d
    ", ans);
        return 0;
    }
  • 相关阅读:
    Random生成随机数
    Jmeter(八)Jmeter监控tomcat
    Jmeter(七)Mongodb的增删改查
    Jmeter(六)文件上传和下载文件
    Jmeter(五)mysql的增删改查
    Jmeter(四)测试webservice脚本
    Jmeter(三)断言和关联
    Jmeter(二)参数化
    Jmeter(一)http接口添加header和cookie
    Python学习笔记(一)数据类型
  • 原文地址:https://www.cnblogs.com/handsomeJian/p/3954412.html
Copyright © 2020-2023  润新知