E. Minimal Segment Cover(dp)

传送门

题意:给你n个线段,m次询问,让你输出n条线段中能完全覆盖询问的线段的最小数量

题解:乍一看有点像区间覆盖问题,但是它n和m给你的是5e5,很大,所以对于询问应该近可能快速的得出答案,同时对于序列的操作也只能在询问前进行;通过对线段的处理,我们可以得到每个点只用一条线段最远能跳到哪个位置,同理用俩条线段最远能跳到哪也可以求出,然后如果跳x条线段之后就大于了右端点,最小数量就是x,如果有不能到的点就可以直接输出-1跳出。

    上面思路可行,但是复杂度和空间都是n平方级别,是不能接受的,但是可以对其进行一定程度的优化,第一维不变,第二维变成跳2的i次方跳线段最远可以到的位置,那么在询问时就变成了如果跳2的i次方会超过询问右端点,那么在当前节点就只向右跳i-1次方,然后从新端点继续往右跳,自到跳一条线段也会大于等于右端点时跳出,输出答案,对于-1的情况判断同上

AC代码:

#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int maxn=5e5+5;
//const ll inf=9223372036854775800;
//const int inf=1e9;
//const int mod=1e9+7;
int rmq[maxn][22],n,m,dp[maxn],er[21];//rmq级录在i节点往后跳2的j次方条线段最多能到哪个点
struct node{
    int li,ri;
};
node y[maxn];
bool cmp(node a,node b){
    return a.li=0;i--){
        rmq[i][0]=dp[i];
        if(dp[i]==-1)
            continue;
        int j;
        for(j=1;rmq[i][j-1]=r){
            ans+=er[a];
            l=rmq[l][a];
            judge=false;
            break;
            }
            else if(rmq[l][a+1]==-1){
                ans=-1;
                break;
            }
        }
        //printf("**%d %d %lld\n",l,r,ans);
        if(ans==-1||judge){
            ans=-1;
            break;
        }
        }
        printf("%lld\n",ans);
    }
}

 

你可能感兴趣的:(ACM,dp)