zoukankan      html  css  js  c++  java
  • 269D

    扫描线+dp

    先对坐标排序,然后·用set维护端点,每次插入左端点,扫描到右端点时删除。每次考虑新插入时分割了哪两个木板,自己分别连边,再删除原来的边,最后dp(好像得维护used,有环)

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int, int> PII;
    const int N = 800010, inf = 2000000010;
    struct data {
        int l, r, h;
        data(int l = 0, int r = 0, int h = 0) : l(l), r(r), h(h) {}
    } ed[N];
    int n, t, cnt;
    int dp[N], used[N];
    PII e[N];
    set<PII> s, m;
    vector<PII> G[N];
    void dfs(int u)
    {
        if(dp[u] == inf || used[u]) return; 
        used[u] = 1;
        for(int i = 0; i < G[u].size(); ++i)
        {
            PII x = G[u][i];
            int v = x.first, w = x.second;
            dfs(v);
            dp[u] = max(dp[u], min(dp[v], w));
        }
    }
    int main()
    {
        scanf("%d%d", &n, &t);
        for(int i = 1; i <= n; ++i)
        {
            int h, l, r; scanf("%d%d%d", &h, &l, &r);
            ed[i] = data(l, r, h);
            e[++cnt] = make_pair(l, i);
            e[++cnt] = make_pair(r, -i);
        }
        sort(e + 1, e + cnt + 1);
        ed[n + 1] = data(-inf, inf, 0);
        ed[n + 2] = data(-inf, inf, t);
        s.insert(make_pair(0, n + 1));
        s.insert(make_pair(t, n + 2));
        for(int i = 1; i <= cnt; ++i)
        {
            int x = e[i].second;
            if(x < 0)
            {
                s.erase(make_pair(ed[-x].h, -x));
                continue;
            }
            PII t = make_pair(ed[x].h, x);
            set<PII> :: iterator it = s.lower_bound(t);
            PII up = *it; 
            --it;
            PII low = *it;
            m.erase(make_pair(up.second, low.second));
            m.insert(make_pair(up.second, x));
            m.insert(make_pair(x, low.second));
            s.insert(t);  
        }
        for(set<PII> :: iterator it = m.begin(); it != m.end(); ++it)
        {
            PII x = *it;
            int len = min(ed[x.second].r, ed[x.first].r) - max(ed[x.second].l, ed[x.first].l);
            G[x.second].push_back(make_pair(x.first, len));
        }
        dp[n + 2] = inf;
        dfs(n + 1);
        printf("%d
    ", dp[n + 1]);
        return 0;
    }
    View Code

    线段树维护+dp

    这个方法好恶心,调了好长时间,边界搞错。

    先离散化坐标,然后按高度排序,正反两次建边。但是一定要注意,边界很恶心,有可能出现1-2,2-3这样的,这样是不相交的。所以右端点要-1就避免了这种情况,因为如果原先只有1单位重合,那么现在不相交了。如果有1单位以上重合,那么现在还是相交的。

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int, int> PII;
    const int M = 300010, inf = 2000000010;
    int n, T, N;
    vector<PII> G[M];
    vector<int> v;
    map<int, int> mp, mir;
    int dp[M], used[M];
    struct data {
        int l, r, h;
    } a[M];
    struct seg {
        int tree[M << 2], tag[M << 2];
        void pushdown(int x)
        {
            if(!tag[x]) return;
            tag[x << 1] = tag[x];
            tag[x << 1 | 1] = tag[x];
            tree[x << 1] = tag[x];
            tree[x << 1 | 1] = tag[x];
            tag[x] = 0;
        }
        void update(int l, int r, int x, int a, int b, int c)
        {
            if(l > b || r < a) return;
            if(l >= a && r <= b)
            {
                tree[x] = tag[x] = c;
                return;
            }
            pushdown(x);
            int mid = (l + r) >> 1;
            update(l, mid, x << 1, a, b, c);
            update(mid + 1, r, x << 1 | 1, a, b, c);
            tree[x] = max(tree[x << 1], tree[x << 1 | 1]);
        }
        int query(int l, int r, int x, int a, int b)
        {
            if(l > b || r < a) return 0;
            if(l >= a && r <= b) return tree[x];
            pushdown(x);
            int mid = (l + r) >> 1;
            return max(query(l, mid, x << 1, a, b), query(mid + 1, r, x << 1 | 1, a, b)); 
        }
    } t;
    void construct(int N, bool flag)
    {
        memset(t.tree, 0, sizeof(t.tree));
        memset(t.tag, 0, sizeof(t.tag));
        for(int i = 1; i < n; ++i)
        {    
            int k = t.query(1, N, 1, a[i].l, a[i].l);
            int low = max(a[i].l, a[k].l), high = min(a[i].r, a[k].r), len = mir[high] - mir[low];    
            int tt = t.query(1, N, 1, low, high - 1);
             if(tt == k && tt)
             {
                if(!flag) G[k].push_back(make_pair(i, len));
                else G[n - i + 1].push_back(make_pair(n - k + 1, len));    
            } 
            k = t.query(1, N, 1, a[i].r - 1, a[i].r - 1);
            low = max(a[i].l, a[k].l), high = min(a[i].r, a[k].r), len = mir[high] - mir[low];    
            tt = t.query(1, N, 1, low, high - 1);
            if(tt == k && tt)
            {
                if(!flag) G[k].push_back(make_pair(i, len));
                else G[n - i + 1].push_back(make_pair(n - k + 1, len));
            }
            t.update(1, N, 1, a[i].l, a[i].r - 1, i);
        }
    }
    void dfs(int u)
    {
        if(used[u] || dp[u] == inf) return;
        used[u] = 1;
        for(int i = 0; i < G[u].size(); ++i)
        {
            PII x = G[u][i];
            int v = x.first, w = x.second;
            dfs(v);
            dp[u] = max(dp[u], min(dp[v], w));
        }
    }
    bool cp(data x, data y)
    {
        return x.h == y.h ? x.l < y.l : x.h < y.h;
    }
    int main()
    {
        scanf("%d%d", &n, &T);
        a[1].h = 0;
        a[n + 2].h = T;
        a[1].l = a[n + 2].l = -inf;
        a[1].r = a[n + 2].r = inf;
        v.push_back(inf);
        v.push_back(-inf);
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d%d%d", &a[i + 1].h, &a[i + 1].l, &a[i + 1].r);
            v.push_back(a[i + 1].l);
            v.push_back(a[i + 1].r);
        }
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(), v.end()), v.end());
        N = v.size();
        for(int i = 0; i < v.size(); ++i)
        {
            mp[v[i]] = i + 1;
            mir[i + 1] = v[i];
        }
        n += 2;
        for(int i = 1; i <= n; ++i)
        {
            a[i].l = mp[a[i].l];
            a[i].r = mp[a[i].r];
        }    
        sort(a + 1, a + n + 1, cp);
        construct(N, false);
        reverse(a + 1, a + n + 1);
        construct(N, true);
        dp[n] = inf;
        dfs(1);
        printf("%d
    ", dp[1]);
        return 0;
    }
    View Code
  • 相关阅读:
    欧拉项目第十题;用筛法做,
    欧拉第十题 求2000000以内的素数之和
    求1000数字中13个相乘最大值
    筛法求10000以内的质数
    判断回文且寻找三位数乘三位数里最大的回文
    分解质因数
    输入一个正整数n,将其转换为二进制后输出。要求定义并调用函数dectobin(n),它的功能是输出
    hdu1863最小生成树krus模板&prim模板
    hdu 3870 最小割转化为最短路径2
    UVALive 3661 最小割转化为最短路径
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7112194.html
Copyright © 2011-2022 走看看