首页 > 代码库 > 269D

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\n", 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\n", dp[1]);
    return 0;
}
View Code

 

269D