zoukankan      html  css  js  c++  java
  • 【BZOJ 1023】[SHOI2008]cactus仙人掌图

    【题目链接】:http://www.lydsy.com/JudgeOnline/problem.php?id=1023

    【题意】

    【题解】

    如果不考虑有环的情况;
    那么有一个经典的求树的直径的方法;
    首先;
    树的直径的两端的端点必然都在树的叶子上(或在根节点,考虑一条链的情况);

    设f[i][0]表示离i这个点最远的叶子节点的距离
    f[i][1]表示离i这个点第二远的叶子节点的距离
    更新的话
    f[x][0]=max(f[son][0]+1);
    f[x][1] = max(second(f[son][0])+1);
    则可以通过dp求出来所有的节点的f值,取max{f[i][0]+f[i][1]}就是它的直径了;
    这里我们可以降成一维的即
    ans = max(ans,f[x]+f[son]+1),f[x]=max(f[son]+1);
    这里f[x]=max(f[son]+1)在ans更新完后才更新;
    这个做法就等同于上面那个做法;
    然后该题的情况就是多了一个环;
    环的话只要通过环上的非最高点对(x,y);
    用f(x)+f(y)+dist(x,y)来更新答案ans;
    设环上的最高点为u;
    然后用非最高点x的f[x]+dist(x,u)来更新f[x]即可;
    挺自然的一个做法吧;
    这里的
    f(x)+f(y)+dist(x,y)
    可以写成
    f[x]+f[y]+x-y
    这里的x和y是把环破成直线之后x和y在直线上的下标;
    x>y
    则我们只要维护f[y]-y不下降就可以了
    用单调队列搞;
    然后因为是最短距离;
    所以f[y]-y必须要满足x-y< n/2
    这里的n是这个环的长度;
    也因为是最短距离;
    所以你要把直线的长度延伸到2*n,不然可能会漏解.

    【完整代码】

    #include <bits/stdc++.h>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define rei(x) scanf("%d",&x)
    #define rel(x) scanf("%lld",&x)
    #define ref(x) scanf("%lf",&x)
    
    typedef pair<int, int> pii;
    typedef pair<LL, LL> pll;
    
    const int dx[9] = { 0,1,-1,0,0,-1,-1,1,1 };
    const int dy[9] = { 0,0,0,-1,1,-1,1,-1,1 };
    const double pi = acos(-1.0);
    const int N = 5e4+100;
    
    int n, m,k,a[N*2],dfn[N],low[N],num,father[N],f[N],dep[N],ans,q[2*N];
    vector <int> g[N];
    
    void input_data()
    {
        rei(n), rei(m);
        rep1(i, 1, m)
        {
            rei(k);
            rep1(j, 1, k)
                rei(a[j]);
            rep1(j, 1, k - 1)
                g[a[j]].push_back(a[j + 1]), g[a[j + 1]].push_back(a[j]);
        }
    }
    
    void dp(int root, int x)
    {
        int n = dep[x] - dep[root] + 1;
        for (int i = x; i != root; i = father[i])
            a[n--] = f[i];
        a[n] = f[root], n = dep[x] - dep[root] + 1;
        rep1(i, n + 1, 2 * n)
            a[i] = a[i - n];
        int h = 1, t = 1;
        q[h] = 1;
        rep1(i, 2, n + n / 2)
        {
            while (h <= t && i - q[h] > n / 2) h++;
            ans = max(ans, a[i] + a[q[h]] + i - q[h]);
            while (h <= t && a[q[h]] - q[h] <= a[i] - i) t--;
            q[++t] = i;
        }
        rep1(i, 2, n)
            f[root] = max(f[root], a[i] + min(i - 1, n - i + 1));
    }
    
    void Tarjan(int x)
    {
        dfn[x] = low[x] = ++num;
        int len = g[x].size();
        rep1(i, 0, len - 1)
        {
            int y = g[x][i];
            if (y == father[x]) continue;
            if (dfn[y] == 0) dep[y] = dep[x] + 1, father[y] = x, Tarjan(y);
            low[x] = min(low[x], low[y]);
            if (dfn[x] < low[y])
                ans = max(ans, f[x] + f[y] + 1), f[x] = max(f[x], f[y] + 1);
        }
        rep1(i, 0, len - 1)
        {
            int y = g[x][i];
            if (y!=father[x] && father[y] != x && dfn[x] < dfn[y])
                dp(x, y);
        }
    }
    
    int main()
    {
        //freopen("F:\rush.txt", "r", stdin);
        input_data();
        Tarjan(1);
        printf("%d
    ", ans);
        //printf("
    %.2lf sec 
    ", (double)clock() / CLOCKS_PER_SEC);
        return 0;
    }
    
  • 相关阅读:
    msp430入门编程41
    msp430入门编程40
    msp430入门编程37
    msp430入门编程36
    msp430入门编程35
    msp430入门编程34
    msp430入门编程33
    msp430入门编程31
    msp430入门编程32
    msp430入门编程30
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626563.html
Copyright © 2011-2022 走看看