• 【BZOJ-4082】Surveillance 树链剖分 LCA + 贪心


    4082: [Wf2014]Surveillance

    Time Limit: 40 Sec  Memory Limit: 128 MB
    Submit: 260  Solved: 100
    [Submit][Status][Discuss]

    Description

    给你一个长度为len的环,以及n个区间,要你选择尽量少的区间,使得它们完全覆盖整个环。问最少要多少个区间。

    Input

    输入数据的第一行是两个整数len和n,代表环的长度以及区间个数。之后n行描述的是n个区间,每个区间分别用一对数字(a,b)表示,若a≤b则表示这个区间覆盖的是[a,b]部分,否则表示这个区间覆盖的是除掉[a+1,b-1]以外的其他部分。

    Output

     输出只有一行,一个整数,代表覆盖整个环所需要的最少区间个数。

    Sample Input

    100 7
    1 50
    50 70
    70 90
    90 40
    20 60
    60 80
    80 20

    Sample Output

    3

    HINT

    Source

    鸣谢qpswwww提供译文

    Solution

    这个题还是很巧妙的啊!

    首先这个题有个序列上的版本在CodeVS,那样只需要贪心的排序,然后从头开始每次选一个覆盖最长的即可。

    但是环上的情况显然不能这么搞,因为可以从每个点开始搞,都会有不同的方法。

    但是这个思路还是可以利用的,我们展环成链,还是贪心的按照右端从小到大排序。

    序列上的版本,我们是直接从起始节点开始每次都选一个覆盖最长的,那这里同样,只有全部是覆盖最长的才有可能是最优的。

    那么我们对每个节点向它覆盖最长的连边,这样会形成一棵树,可以发现,这样树上两点的距离就是答案。

    所以我们求一下LCA,枚举一下每个点做起始时的答案,取一下min即可。

    还是有很多细节需要处理的,比如我们很有可能会覆盖过多,所以最后并不是每次查$i->i+L$,所以我们需要一开始用一个set维护一下这个东西。

    这样总的复杂度大概是$O(NlogN)$,范围大概是$10^{6}$的,有点虚所以写的链剖

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    using namespace std;
    #define INF 0x7fffffff
    inline int read()
    {
        int x=0; char ch=getchar();
        while (ch<'0' || ch>'9') {ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x;
    }
    #define MAXN 1000010
    struct SecNode
    {
        int s,t;
        bool operator < (const SecNode & A) const {return t==A.t? s<A.s:t<A.t;}
    }sec[MAXN];
    struct EdgeNode{int next,to;}edge[MAXN<<2];
    int head[MAXN<<1],cnt=1;
    inline void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
    inline void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}
    int size[MAXN<<1],fa[MAXN<<1],deep[MAXN<<1],son[MAXN<<1],top[MAXN<<1];
    bool ok[MAXN<<1];
    int N,L,ans=INF;
    set<int>st;
    inline void DFS_1(int now)
    {
        if (deep[now]) return;
        if (!fa[now]) 
            {
                deep[now]=1;
                if (now>L && ok[now]) fa[now]=2*L+1,InsertEdge(fa[now],now);
                return;
            }
        DFS_1(fa[now]);
        InsertEdge(fa[now],now);
        deep[now]=deep[fa[now]]+1;
    }
    inline void DFS_2(int now)
    {
        size[now]=1;
        for (int i=head[now]; i; i=edge[i].next)
            if (edge[i].to!=fa[now])
                {
                    DFS_2(edge[i].to);
                    size[now]+=size[edge[i].to];
                    if (size[son[now]]<size[edge[i].to]) son[now]=edge[i].to;
                }
    }
    inline void DFS_3(int now,int chain)
    {
        top[now]=chain;
        if (son[now]) DFS_3(son[now],chain);
        for (int i=head[now]; i; i=edge[i].next)
            if (edge[i].to!=son[now] && edge[i].to!=fa[now])
                DFS_3(edge[i].to,edge[i].to);
    }
    inline int LCA(int u,int v)
    {
        v=*st.lower_bound(v);
        if (!top[u] || !top[v]) return -1;
        while (top[u]!=top[v])
            {
                if (deep[top[u]]<deep[top[v]]) swap(u,v);
                u=fa[top[u]];
            }
        if (deep[u]>deep[v]) swap(u,v);
        return u;
    }
    
    int main()
    {
        L=read(),N=read();
        for (int i=1; i<=N; i++) sec[i].s=read(),sec[i].t=read(),sec[i].t=sec[i].t<sec[i].s? sec[i].t+L:sec[i].t;
        sort(sec+1,sec+N+1);
        for (int i=N; i; i--)
            if (!fa[sec[i].s]) 
                for (int j=sec[i].s; j<=L && j<=sec[i].t && !fa[j]; j++)
                    {ok[ fa[j]=sec[i].t+1 ]=1; if (fa[j]>L) st.insert(fa[j]);}
        st.insert(2*L+2);
        for (int i=1; i<=L*2; i++) DFS_1(i);
        DFS_2(2*L+1); DFS_3(2*L+1,2*L+1);
        for (int lca,i=1; i<=L; i++) lca=LCA(i,i+L),ans=lca!=-1? min(ans,deep[i]-deep[lca]):ans;
        if (ans==INF) puts("impossible"); else printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    Axure RP使用攻略--动态面板滑动效果(10)
    Axure RP使用攻略--带遮罩层的弹出框(9)
    Axure RP使用攻略--动态面板的用途(8)
    Axure RP使用攻略--入门级(七)之axure元件使用思路的补充
    Axure RP使用攻略--入门级(六)关于Axure rp触发事件中IF和ELSE IF的使用说明
    Axure RP使用攻略--入门级(五)系统函数与变量
    Axure RP使用攻略--入门级(四)条件生成器
    Axure RP使用攻略--入门级(三)元件的触发事件
    Altium Designer 14安装破解
    小米手环暴力拆解
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5917689.html
Copyright © 2020-2023  润新知