4444: [Scoi2015]国旗计划|贪心|倍增

来源:互联网 发布:济南市社保查询软件 编辑:程序博客网 时间:2024/06/15 19:53

因为没有区间被其他区间包含这个条件,也就是如果li<lj那么一定满足ri<rj,就可以贪心搞一搞了。
假如区间[l,r]都已经被覆盖,那么可以继续找一个li[l,r]范围内的最大的一个,继续扩展覆盖的区间,然后再以同样的方式找下一个战士
这样可以按照左端点排序,然后每一个战士要找的下一个战士都是确定的,然后用倍增找出一共需要多少战士就可以了

#include<algorithm>#include<iostream>#include<cstdlib>#include<cstring>#include<cstdio>#include<vector>#include<cmath>#include<queue>#include<set>#include<map>#define ll long long#define N 402020#define pa pair<int,int>using namespace std;int sc(){    int i=0,f=1; char c=getchar();    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}    while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();    return i*f;}struct W{int l,r,p;}a[N];int n,m,tot,fa[N][19],ans[N];set<pa>st;bool cmp(W a,W b){    return a.l<b.l;}void solve(int x){    int p=a[x].p,L=a[x].l+m;    for(int i=18;i>=0;i--)        if(fa[x][i])            if(a[fa[x][i]].r<L)                x=fa[x][i],ans[p]+=(1<<i);}int main(){    n=sc(),m=sc();    for(int i=1;i<=n;i++)    {        a[++tot].l=sc(),a[tot].r=sc(),a[tot].p=i;        if(a[tot].r<a[tot].l)a[tot].r+=m;        ++tot;        a[tot].l=a[tot-1].l+m;        a[tot].r=a[tot-1].r+m;    }    sort(a+1,a+tot+1,cmp);      st.insert(make_pair(a[tot].l,tot));    for(int i=tot-1;i;i--)    {        fa[i][0]=(--st.upper_bound(make_pair(a[i].r,0x7FFFFFFF)))->second;        st.insert(make_pair(a[i].l,i));    }    for(int i=1;i<=18;i++)        for(int j=tot;j;j--)            fa[j][i]=fa[fa[j][i-1]][i-1];    for(int i=1;i<=tot;i++)        if(a[i].p)            solve(i);    for(int i=1;i<=n;i++)        printf("%d ",ans[i]+2);    return 0;}
0 0