您的位置:首页 > 其它

BZOJ 4444 [Scoi2015]国旗计划

2017-01-28 00:17 363 查看
破环为链+离散化+倍增

环上问题一般转化为链上问题。本题破环为链之后再在末尾复制一条链,那么一个环上覆盖就等价于一个i~i+m的链上覆盖。

对每一个点维护从它的左边最远能跳到的右边的点。发现这是一个树形结构。因此对于每一个询问i,倍增从r[i]往上跳找到第一个点j满足j≥l[i]+m。这样O(n*log^2)

还注意到每个人的答案之差最多为1。假设不强制取任何人,此时最优解为A,那么显然强制取一个人的解是A或A+1。所以只要判一两个解是否合法即可。这样O(n*log)

#include<cstdio>
#include<algorithm>
#define N 400005
#define H 20
using namespace std;
namespace runzhe2000
{
const int INF = 1<<30;
int n, m, arr
, arr_cnt, l
, r
, fa[N*2][H];
struct interval{int l, r;}inter
;
bool cmp(interval a, interval b){return a.l < b.l;}
int jump(int x, int k)
{
if(k < 0) return -1;
for(int i = H-1; ~i; i--)
if(k&(1<<i)) x = fa[x][i];
return x;
}
void main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
{
scanf("%d%d",&l[i],&r[i]);
arr[++arr_cnt] = l[i];
arr[++arr_cnt] = r[i];
}
sort(arr+1, arr+1+arr_cnt);
arr_cnt = unique(arr+1, arr+1+arr_cnt) - arr - 1;
int mx = 0;
for(int i = 1; i <= n; i++)
{
l[i] = lower_bound(arr+1, arr+1+arr_cnt, l[i]) - arr;
r[i] = lower_bound(arr+1, arr+1+arr_cnt, r[i]) - arr;
mx = max(mx, max(l[i], r[i]));
}
for(int i = 1; i <= n; i++)
{
if(l[i] > r[i]) r[i] += mx;
l[i+n] = l[i] + mx;
r[i+n] = r[i] + mx;
if(r[i+n] > 2*mx) r[i+n] = 2*mx;
inter[i] = (interval){l[i], r[i]};
inter[i+n] = (interval){l[i+n], r[i+n]};
}
sort(inter+1, inter+1+2*n, cmp);
int far = 0;
for(int i = 1, pos = 1; i <= mx*2; i++)
{
for(; pos <= 2*n && inter[pos].l <= i; pos++)far = max(far, inter[pos].r);
fa[i][0] = far;
}
for(int i = mx*2; i; i--)
for(int j = 1; j < H; j++)
fa[i][j] = fa[fa[i][j-1]][j-1];
int L = 0, R = n;
for(; L < R; )
{
int mid = (L+R)>>1;
if(jump(r[1], mid) >= l[1]+mx) R = mid;
else L = mid + 1;
}
printf("%d",L + 1);
for(int i = 2; i <= n; i++)
{
if(jump(r[i], L-1) >= l[i]+mx) printf(" %d",L);
else if(jump(r[i], L) >= l[i]+mx) printf(" %d",L + 1);
else printf(" %d",L + 2);
}
}
}
int main()
{
runzhe2000::main();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: