[ 杂题 ] [ SCOI2014 ] BZOJ4444

断环为链。将端点离散,令 fi 表示左端点小于等于 i 的右端点的最大值。那么显然当右端点为 i 时会走到 fi ,直到当前点与左端点距离大于等于 m
因为每个区间的答案一定小于等于最优答案加 1,所以不同区间的答案不会超过 1 。根据 fi 建树, dfs 时维护一个指针就好了。

#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void Read(int& x){
    char c=nc();
    for(;c<'0'||c>'9';c=nc());
    for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());
}
#define fi first
#define se second
typedef pair<int,int> abcd;
const int N=400010;
vector<int>g[N<<1];
int q[N<<1],R;
abcd c[N<<1];
int k,n,m,p;
int l[N],r[N];
int f[N<<1],Ans[N<<1];
int num,cnt;
int x,y,top,d[N<<1];
void Dfs(int x,int y){
    d[x]=y;
    while(p<R-1&&q[p+1]>=x+m)p++;
    if(x<=num)Ans[x]=d[x]-d[q[p]];
    q[R++]=x;
    for(int i=0;i<g[x].size();i++){
        Dfs(g[x][i],y+1);
        while(p&&q[p]<x+m)p--;
        R--;
    }
}
int main(){
    Read(n);Read(m);
    for(int i=1;i<=n;i++)Read(x),Read(y),c[++cnt]=abcd(x,i),c[++cnt]=abcd(y,i+n);
    sort(c+1,c+cnt+1);
    for(int i=1;i<=cnt;i++){
        if(c[i].fi!=c[i-1].fi)num++;
        if(c[i].se>n)r[c[i].se-n]=num;else l[c[i].se]=num;
    }
    if(c[cnt].fi<m)m=++num;else m=num;
    for(int i=1;i<=n;i++)
    if(r[i]>=l[i]){
        f[l[i]]=max(f[l[i]],r[i]);
        f[l[i]+num]=max(f[l[i]+num],r[i]+num);
    }else{
        f[1]=max(f[1],r[i]);
        f[l[i]]=max(f[l[i]],r[i]+num);
        f[l[i]+num]=max(f[l[i]+num],num<<1);
    }
    for(int i=1;i<=(num<<1);i++){
        f[i]=max(f[i],f[i-1]);
        if(f[i]>i)g[f[i]].push_back(i);
    }
    for(int i=num+1;i<=(num<<1);i++)
    if(f[i]<=i)p=R=0,Dfs(i,0);
    for(int i=1;i<=n;i++)printf("%d ",Ans[l[i]]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值