题目描述

  有\(n\)个人和一条长度为\(t\)的线段,每个人还有一个工作范围(是一个区间)。最开始整条线段都是白的。定义每个人的工作长度是这个人的工作范围中白色部分的长度(会随着线段改变而改变)。每一天开始时你要选择一个人满足这个人的工作长度最小(如果有多个就选编号最小的)。把这个人的工作区间染黑。请你输出每天你选了哪个人。

  保证工作范围中左端点和右端点单调递增。

  \(n\leq 300000\)

题解

  先把线段离散化成很多个小区间,那么每个小区间只会被染黑一次(染黑之后不会变白)。

  因此每次选择了一个人后可以暴力把这个人的工作范围内白色的区间染黑,那么覆盖了这个区间的人就会受到影响。

  观察到左右端点都单调递增,所以覆盖一个区间的人就是连续的。

  直接用线段树维护每个人当前的工作长度。

  用并查集维护右边的第一个白色区间。

  时间复杂度:\(O(n\log n)\)

代码

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<utility>
#include<cstring>
using namespace std;
typedef pair<int,int> pii;
int a[2000010];
int c[2000010];
int d[2000010];
int f[2000010];
int l[2000010];
int r[2000010];
int s[2000010];
int rt;
namespace seg
{
struct node
{
int l,r,ls,rs;
int t;
pii s;
node()
{
l=r=ls=rs=t=0;
}
};
node a[2000010];
int cnt;
void build(int &p,int l,int r)
{
p=++cnt;
a[p].l=l;
a[p].r=r;
if(l==r)
{
a[p].s=pii(::s[l],l);
return;
}
int mid=(l+r)>>1;
build(a[p].ls,l,mid);
build(a[p].rs,mid+1,r);
a[p].s=min(a[a[p].ls].s,a[a[p].rs].s);
}
void add(int p,int v)
{
a[p].t+=v;
a[p].s.first+=v;
}
void push(int p)
{
if(a[p].t&&a[p].l!=a[p].r)
{
add(a[p].ls,a[p].t);
add(a[p].rs,a[p].t);
a[p].t=0;
}
}
void add(int p,int l,int r,int v)
{
if(l<=a[p].l&&r>=a[p].r)
{
add(p,v);
return;
}
push(p);
int mid=(a[p].l+a[p].r)>>1;
if(l<=mid)
add(a[p].ls,l,r,v);
if(r>mid)
add(a[p].rs,l,r,v);
a[p].s=min(a[a[p].ls].s,a[a[p].rs].s);
}
void gao(int p,int x)
{
if(a[p].l==a[p].r)
{
a[p].s.first=0x7fffffff;
return;
}
push(p);
int mid=(a[p].l+a[p].r)>>1;
if(x<=mid)
gao(a[p].ls,x);
else
gao(a[p].rs,x);
a[p].s=min(a[a[p].ls].s,a[a[p].rs].s);
}
int get(int p,int x)
{
if(a[p].l==a[p].r)
return a[p].s.first;
push(p);
int mid=(a[p].l+a[p].r)>>1;
if(x<=mid)
return get(a[p].ls,x);
else
return get(a[p].rs,x);
}
}
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
int b[1000010];
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
int n,t;
scanf("%d%d",&t,&n);
int m=0;
int i;
memset(a,0,sizeof a);
memset(c,0,sizeof c);
memset(d,0,sizeof d);
memset(f,0,sizeof f);
memset(s,0,sizeof s);
memset(l,0,sizeof l);
memset(r,0,sizeof r);
for(i=1;i<=n;i++)
{
scanf("%d%d",&l[i],&r[i]);
r[i]--;
s[i]=r[i]-l[i]+1;
a[++m]=l[i];
a[++m]=r[i]+1;
}
sort(a+1,a+m+1);
m=unique(a+1,a+m+1)-a-1;
for(i=1;i<=n;i++)
{
int x=l[i],y=r[i];
l[i]=lower_bound(a+1,a+m+1,l[i])-a;
r[i]=lower_bound(a+1,a+m+1,r[i]+1)-a-1;
if(a[l[i]]!=x)
printf("error\n");
if(a[r[i]+1]!=y+1)
printf("error\n");
if(l[i]<=l[i-1])
printf("error\n");
if(r[i]<=r[i-1])
printf("error\n");
}
seg::cnt=0;
rt=0;
seg::build(rt,1,n);
for(i=1;i<=m;i++)
{
c[i]=a[i+1]-a[i];
f[i]=i;
}
f[m+1]=m+1;
int j;
for(i=1;i<=n;i++)
{
pii ans=seg::a[rt].s;
// printf("%d %d\n",seg::get(rt,7396),seg::get(rt,20692));
printf("%d\n",ans.second);
// seg::add(rt,ans.second,ans.second,0x7fffffff-ans.first);
seg::gao(rt,ans.second);
// for(j=l[ans.second];j<=r[ans.second];j++)
// if(!b[j])
// {
// b[j]=1;
for(j=find(l[ans.second]);j<=r[ans.second];j=find(j))
{
int x=lower_bound(r+1,r+n+1,j)-r;
int y=upper_bound(l+1,l+n+1,j)-l-1;
if(x<=y)
{
// if(r[x-1]>=j)
// printf("error1\n");
// if(l[y+1]<=j)
// printf("error2\n");
seg::add(rt,x,y,-c[j]);
}
// else
// if(l[7396]<=j&&r[7396]>=j)
// seg::add(rt,7396,7396,-c[j]);
f[j]=j+1;
}
}
return 0;
}

【XSY2707】snow 线段树 并查集的更多相关文章

  1. 【BZOJ 4662】 4662: Snow (线段树+并查集)

    4662: Snow Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 136  Solved: 47 Description 2333年的某一天,临冬突 ...

  2. [WC2005]双面棋盘(线段树+并查集)

    线段树+并查集维护连通性. 好像 \(700ms\) 的时限把我的常数超级大的做法卡掉了, 必须要开 \(O_2\) 才行. 对于线段树的每一个结点都开左边的并查集,右边的并查集,然后合并. \(Co ...

  3. 2022.02.27 CF811E Vladik and Entertaining Flags(线段树+并查集)

    2022.02.27 CF811E Vladik and Entertaining Flags(线段树+并查集) https://www.luogu.com.cn/problem/CF811E Ste ...

  4. 【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集

    3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[Submit][Status ...

  5. bzoj 2054: 疯狂的馒头(线段树||并查集)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2054 线段树写法: 点的颜色只取决于最后一次染的颜色,所以我们可以倒着维护,如果当前区间之前 ...

  6. 【CF687D】Dividing Kingdom II 线段树+并查集

    [CF687D]Dividing Kingdom II 题意:给你一张n个点m条边的无向图,边有边权$w_i$.有q个询问,每次给出l r,问你:如果只保留编号在[l,r]中的边,你需要将所有点分成两 ...

  7. 【BZOJ1453】[Wc]Dface双面棋盘 线段树+并查集

    [BZOJ1453][Wc]Dface双面棋盘 Description Input Output Sample Input Sample Output HINT 题解:话说看到题的第一反应其实是LCT ...

  8. codeforces 811E Vladik and Entertaining Flags(线段树+并查集)

    codeforces 811E Vladik and Entertaining Flags 题面 \(n*m(1<=n<=10, 1<=m<=1e5)\)的棋盘,每个格子有一个 ...

  9. 【Codeforces811E】Vladik and Entertaining Flags [线段树][并查集]

    Vladik and Entertaining Flags Time Limit: 20 Sec  Memory Limit: 512 MB Description n * m的矩形,每个格子上有一个 ...

随机推荐

  1. 使用PL/SQL连接Oracle时报错ORA-12541: TNS: 无监听程序

    因公司需求,安装oracle数据库,oracle数据库用账号密码可以登录,然后在pl/sql里面不能登录,显示无监听程序. 这就说明可能有些服务没有启动,开始运行services.msc ,进入后寻找 ...

  2. [转帖]关于CPU Cache -- 程序猿需要知道的那些事

    关于CPU Cache -- 程序猿需要知道的那些事 很早之前读过作者的blog 记得作者在facebook 工作.. 还写过mysql相关的内容 大拿 本文将介绍一些作为程序猿或者IT从业者应该知道 ...

  3. [转帖]Linux分页机制之概述--Linux内存管理(六)

    Linux分页机制之概述--Linux内存管理(六) 2016年09月01日 19:46:08 JeanCheng 阅读数:5491 标签: linuxkernel内存管理分页架构更多 个人分类: ┈ ...

  4. Git本地仓库push至GitHub远程仓库每次输入账户密码问题解决(亲测可行)

    在使用git push命令将本地仓库内容推送至GitHub远程仓库的每一次git都要让我们输入GitHub的用户名和密码.这着实让我们心烦.我们会有疑问,我明明设置了公钥呀!怎么还需要输入账户和密码? ...

  5. 2.请介绍一下List和ArrayList的区别,ArrayList和HashSet区别

    第一问: List是接口,ArrayList实现了List接口. 第二问: ArrayList实现了List接口,HashSet实现了Set接口,List和Set都是继承Collection接口. A ...

  6. 【gedit】 显示行号

    打开gedit文本编辑器->Edit(编辑)->preferences(预设)->view(视图)->在Display line numbers前打勾->close

  7. php 将数组转换网址URL参数

    $array =array ( 'id' =123, 'name' = 'dopost' );echo http_build_query( $array );//得到结果id=123name=dopo ...

  8. 读懂掌握 Python logging 模块源码 (附带一些 example)

    搜了一下自己的 Blog 一直缺乏一篇 Python logging 模块的深度使用的文章.其实这个模块非常常用,也有非常多的滥用.所以看看源码来详细记录一篇属于 logging 模块的文章. 整个 ...

  9. C#通过Socket读取大量数据

    在C#中经常会用到Socket去接收和发送数据,而且也是非常方便的,有时候我们会向服务端去请求数据,如果返回的数据量很大,比如超过10M甚至是更多,那么该怎样去接收数据呢?下面以一个在项目中用到的实例 ...

  10. PHP的爬虫框架

    Beanbun PHPSpider PHPQuery QueryList PHPCrawer Snoopy