bzoj4383(拓扑排序)
给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r,k以及接下来k个正整数,表示a[l],a[l+1],...,a[r-1],a[r]里这k个数中的任意一个都比任意一个剩下的r-l+1-k个数大(严格大于,即没有等号)。请任意构造出一组满足条件的方案,或者判断无解。
Solution
这个模型有点像差分约束系统,但是建图复杂度过高。
考虑到每次一个区间内的k个数将整段序列划分为k+1个区间,所以我们考虑用线段树优化这个过程,每次建一个s点和这k个点连边,再和剩下的数所对应的区间连边,这样就保证了我们建图的复杂度。
然后题目中给的数域是1-1e9,有两种方法,一种是从极小向大里跑,另一种是从极大往小里跑。
如果是前一种,那么我的转移顺序必须为从小到大,回顾我们的连边,发现需要从一堆区间向S走,但是这一堆区间需要下面的节点转移而来,所以我们在线段树上连边的方式为从下往上连。
后一种反之。
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define N 400002
#define M 4000003
using namespace std;
queue<int>q;
int head[N],tot,du[N],ji[N],anti_ji[N],top,rs[N],ls[N],s,n,m,pos,ss,x,a[N],l,r,k,num[N],tag;
struct node{
int n,to,l;
}e[M];
inline void add(int u,int v,int l){
e[++tot].n=head[u];
e[tot].to=v;
e[tot].l=l;du[v]++;
head[u]=tot;
}
void build(int cnt,int l,int r){
if(l==r){ji[l]=cnt;anti_ji[cnt]=l;return;}
int mid=(l+r)>>;
ls[cnt]=++top;rs[cnt]=++top;
add(ls[cnt],cnt,);add(rs[cnt],cnt,);
build(ls[cnt],l,mid);build(rs[cnt],mid+,r);
}
void query(int cnt,int l,int r,int L,int R){
if(l>=L&&r<=R){
add(cnt,s,);
return;
}
int mid=(l+r)>>;
if(mid>=L)query(ls[cnt],l,mid,L,R);
if(mid<R)query(rs[cnt],mid+,r,L,R);
}
int main(){
top=;
scanf("%d%d%d",&n,&ss,&m);
for(int i=;i<=ss;++i)scanf("%d%d",&pos,&x),a[pos]=x;
build(,,n);
for(int i=;i<=m;++i){
scanf("%d%d%d",&l,&r,&k);int p=l;s=++top;
for(int j=;j<=k;++j){
scanf("%d",&x);add(s,ji[x],);
if(x>p)query(,,n,p,x-);
p=x+;
}
if(p<=r)query(,,n,p,r);
}
for(int i=;i<=top;++i){
if(!du[i])q.push(i),num[i]=;
if(a[anti_ji[i]])num[i]=a[anti_ji[i]];
}
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i;i=e[i].n){
int v=e[i].to,x=num[u]+e[i].l;
if(!--du[v])q.push(v);
if(!a[anti_ji[v]]){
num[v]=max(num[v],x);
}
else{
num[v]=a[anti_ji[v]];
if(a[anti_ji[v]]<x)tag=;
}
}
}
for(int i=;i<=top;++i)if(du[i])tag=;
for(int i=;i<=n;++i)if(num[ji[i]]>1e9||!num[ji[i]])tag=;
if(tag){
printf("NIE\n");
return ;
}
printf("TAK\n");
for(int i=;i<=n;++i)printf("%d ",num[ji[i]]);
return ;
}
Code2
#include<iostream>
#include<cstdio>
#include<queue>
#define N 400002
#define M 4000003
using namespace std;
queue<int>q;
int head[N],tot,du[N],ji[N],anti_ji[N],top,rs[N],ls[N],s,n,m,pos,ss,x,a[N],l,r,k,num[N],tag;
struct node{
int n,to,l;
}e[M];
inline void add(int u,int v,int l){
e[++tot].n=head[u];
e[tot].to=v;
e[tot].l=l;du[v]++;
head[u]=tot;
}
void build(int cnt,int l,int r){
if(l==r){ji[l]=cnt;anti_ji[cnt]=l;return;}
int mid=(l+r)>>;
ls[cnt]=++top;rs[cnt]=++top;
add(cnt,ls[cnt],);add(cnt,rs[cnt,);
build(ls[cnt],l,mid);build(rs[cnt],mid+,r);
}
void query(int cnt,int l,int r,int L,int R){
if(l>=L&&r<=R){
add(s,cnt,);
return;
}
int mid=(l+r)>>;
if(mid>=L)query(ls[cnt],l,mid,L,R);
if(mid<R)query(rs[cnt],mid+,r,L,R);
}
int main(){
top=;
scanf("%d%d%d",&n,&ss,&m);
for(int i=;i<=ss;++i)scanf("%d%d",&pos,&x),a[pos]=x;
build(,,n);
for(int i=;i<=m;++i){
scanf("%d%d%d",&l,&r,&k);int p=l;s=++top;
for(int j=;j<=k;++j){
scanf("%d",&x);add(ji[x],s,);
if(x>p)query(,,n,p,x-);
p=x+;
}
if(p<=r)query(,,n,p,r);
}
for(int i=;i<=top;++i){
if(!du[i])q.push(i);
num[i]=1e9;
}
while(!q.empty()){
int u=q.front();q.pop();if(anti_ji[u]&&!num[u])num[u]=1e9;
for(int i=head[u];i;i=e[i].n){
int v=e[i].to,x=num[u]-e[i].l;
if(!--du[v])q.push(v);
if(!a[anti_ji[v]]){
num[v]=min(num[v],x);
}
else{
num[v]=a[anti_ji[v]];
if(a[anti_ji[v]]>x)tag=;
}
}
}
for(int i=;i<=top;++i)if(du[i])tag=;
if(tag){
printf("NIE\n");
return ;
}
printf("TAK\n");
for(int i=;i<=n;++i)printf("%d ",num[ji[i]]);
return ;
}
bzoj4383(拓扑排序)的更多相关文章
- BZOJ4383 Pustynia(线段树+拓扑排序)
线段树优化建图暴力拓扑排序即可.对于已确定的数,拓扑排序时dp,每个节点都尽量取最大值,如果仍与已确定值矛盾则无解.叶子连出的边表示大于号,其余边表示大于等于. #include<iostrea ...
- [POI2015][bzoj4383] Pustynia [线段树优化建图+拓扑排序]
题面 bzoj权限题传送门 luogu传送门 思路 首先,这个题目显然可以从所有小的点往大的连边,然后如果没环就一定可行,从起点(入读为0)开始构造就好了 但是问题来了,如果每个都连的话,本题中边数是 ...
- 【bzoj4383】[POI2015]Pustynia 线段树优化建图+差分约束系统+拓扑排序
题目描述 给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r,k以及接下来k个正整数,表示a[l],a[l+1],...,a[r- ...
- BZOJ4383 [POI2015]Pustynia[线段树优化建边+拓扑排序+差分约束]
收获挺大的一道题. 这里的限制大小可以做差分约束,从$y\to x$连$1$,表示$y\le x-1$即$y<x$,然后跑最长路求解. 但是,如果这样每次$k+1$个小区间每个点都向$k$个断点 ...
- bzoj4383 [POI2015]Pustynia 拓扑排序+差分约束+线段树优化建图
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4383 题解 暴力的做法显然是把所有的条件拆分以后暴力建一条有向边表示小于关系. 因为不存在零环 ...
- 算法与数据结构(七) AOV网的拓扑排序
今天博客的内容依然与图有关,今天博客的主题是关于拓扑排序的.拓扑排序是基于AOV网的,关于AOV网的概念,我想引用下方这句话来介绍: AOV网:在现代化管理中,人们常用有向图来描述和分析一项工程的计划 ...
- 有向无环图的应用—AOV网 和 拓扑排序
有向无环图:无环的有向图,简称 DAG (Directed Acycline Graph) 图. 一个有向图的生成树是一个有向树,一个非连通有向图的若干强连通分量生成若干有向树,这些有向数形成生成森林 ...
- 【BZOJ-2938】病毒 Trie图 + 拓扑排序
2938: [Poi2000]病毒 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 609 Solved: 318[Submit][Status][Di ...
- BZOJ1565 [NOI2009]植物大战僵尸(拓扑排序 + 最大权闭合子图)
题目 Source http://www.lydsy.com/JudgeOnline/problem.php?id=1565 Description Input Output 仅包含一个整数,表示可以 ...
随机推荐
- 从Mongo导出数据库到Excel
在MongoDB的安装目录的bin文件夹下打开命令行: ./mongoexport -d kugou_db -c songs -f rank,singer,song,time --type=csv - ...
- 中国科学技术大学统一身份认证系统CAS
CAS | Apereohttps://www.apereo.org/projects/cas 中国科学技术大学统一身份认证系统https://passport.ustc.edu.cn/login?s ...
- 分布式文件系统FastDFS
fastdfs_百度百科https://baike.baidu.com/item/fastdfs/5609710 用FastDFS一步步搭建文件管理系统 - bojiangzhou - 博客园http ...
- Linux 光盘挂载步骤
mount -t fs_type device dir 挂载操作 常见的文件系统类型 Windows :ntfs.fat32 Linux:ext3.ext4.xfs 光盘: iso9660 挂载光盘: ...
- Spring在web开发中的应用
(1)在 web 项目中要使用 spring 需要导入一个 jar 包: spring-web-4.2.4.jar包 (2)在 web.xml 文件中配置 Listener <listener& ...
- 运行Spark-shell,解决Unable to load native-hadoop library for your platform
启动spark后,运行bin/spark-shell会出现一个警告 提君博客原创 WARN util.NativeCodeLoader: Unable to load native-hadoop li ...
- js获取数组中相同元素数量
<script> var array = new Array(1,2,5,1,4,4,2,3,5,1,1,5,5,5,6,7,3,9,9,10); var arr = new Array( ...
- 动态SQL3
Oracle的批量操作 Oracle不支持VALUES(),(),()这种方式,所以不能用上一节所讲的方法. 有时候业务会包含很多次数据库操作,为了减少数据库连接,我们会选择一次提交大量sql, 这时 ...
- U68641 划水(swim.pas/c/cpp)
U68641 划水(swim.pas/c/cpp) 题目背景 小小迪带你划水. 题目描述 原题 输入输出格式 输入格式: 第一行一个数 T. 接下来 T 行每行一个数表示 n 输出格式: 输出 T 行 ...
- 实验吧 WEB 头有点大
看到了良心的提示,http header,之后看到了要求.NET framework 9.9 英国 IE,我想想.NET好像还没有更新到9.9,就无视了这重要的提示. 我就看了一眼题解,发现burps ...