luoguP3588_[POI2015]PUS
题意
有一个\(n\)个数的序列,已知其中的\(k\)个数,然后有\(m\)个信息,每个信息给出区间\([l,r]\),和\(k\)个数,表示区间\([l,r]\)中这\(k\)个数大于剩下的\(r-l+1-k\)个数,求出一个方案。
分析
- 抄做的第一题线段树优化建图的题目,很巧妙。
- 大小关系我们可以看成是一条有向边,由小数连向大数,而两数之差就是边权,最后跑一遍拓扑排序,从最小的值更新,判断是否有环或者数值超过范围即可。
- 对于每一个信息,如果将大的数和小的数暴力两两连边,显然不行。
- 第一个优化是在两个数集之间加一个虚点,小数连向虚点,虚点连向大数,就相当于两两连边了,不过这样还是不够。
- 第二个优化就是用线段树来优化建图,因为给定的\(k\)个数其实是将区间\([l,r]\)分成\(k+1\)个小区间,这些小数集合,其实并不需要一一连边,只需要整个区间连向虚点即可。
代码
#include <bits/stdc++.h>
using namespace std;
#define ls i<<1
#define rs i<<1|1
#define mid (l+r)/2
const int N=5e5+50;
const int INF=1e9;
struct Edge{
int v,w,next;
}e[N*10];
int cnt,head[N],ind[N];
int n,s,m,l,r,k,x,a[N];
void init(){
cnt=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w){
e[cnt]=Edge{v,w,head[u]};
head[u]=cnt++;
ind[v]++;
}
//记录每个线段树节点的实际编号(图论中的节点)
int pt[N],tot;
void build(int i,int l,int r){
if(l==r){
pt[i]=l;
return;
}
pt[i]=++tot;
build(ls,l,mid);
build(rs,mid+1,r);
add(pt[ls],pt[i],0);
add(pt[rs],pt[i],0);
}
//线段树区间[ql,qr]对应的节点连向x(图)
void link(int i,int l,int r,int ql,int qr,int x){
if(ql<=l && qr>=r){
add(pt[i],x,0);
return;
}
if(ql<=mid){
link(ls,l,mid,ql,qr,x);
}
if(qr>mid){
link(rs,mid+1,r,ql,qr,x);
}
}
int ans[N],vis[N];
bool topo(){
queue<int> q;
int c=0;
for(int i=1;i<=tot;i++){
if(!ind[i]){
q.push(i);
}
if(!ans[i]){
//还不确定的数
ans[i]=1;
}
}
while(!q.empty()){
int u=q.front();
q.pop();
c++;
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].v;
int w=e[i].w;
ans[v]=max(ans[v],ans[u]+w);
if(a[v] && ans[v]>a[v]){
return false;
}
--ind[v];
if(!ind[v]){
q.push(v);
}
}
}
return c==tot;
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d%d",&n,&s,&m);
init();
//线段树n个叶子节点1-n,然后其他父节点就++tot
tot=n;
build(1,1,n);
for(int i=1;i<=s;i++){
scanf("%d%d",&k,&x);
a[k]=ans[k]=x;
}
//对于给定的k个数也就是集合S1,都大于等于[l,r]剩下的数S2,因此需要两两连边
//优化1 建立虚点,S2连向虚点,虚点连向S1
//优化2 S2都是一些连续区间,可以用线段树来优化建图,让线段树区间连向虚点
for(int i=1;i<=m;i++){
scanf("%d%d%d",&l,&r,&k);
tot++;
int p=l-1;
//k个数将区间分为k+1段,对应的线段树区间分别连向虚点
for(int j=1;j<=k;j++){
scanf("%d",&x);
//虚点连向S1
add(tot,x,1);
//连续区间连向虚点
if(x>p+1){
//和上一个点之间有一段连续区间
link(1,1,n,p+1,x-1,tot);
}
p=x;
}
if(x<r){
link(1,1,n,x+1,r,tot);
}
}
//拓扑排序求出方案
bool flag=topo();
if(!flag){
printf("NIE\n");
return 0;
}
for(int i=1;i<=n;i++){
if(ans[i]>INF){
printf("NIE\n");
return 0;
}
}
printf("TAK\n");
for(int i=1;i<=n;i++){
printf("%d%c",ans[i],i==n?'\n':' ');
}
return 0;
}
luoguP3588_[POI2015]PUS的更多相关文章
- P3588 [POI2015]PUS(拓扑排序+线段树)
P3588 [POI2015]PUS 对于每个$(l,r,k)$,将$k$个位置向剩下$r-l-k+1$个位置连边,边权为$1$,这样就保证$k$个位置比剩下的大 先给所有位置填$1e9$保证最优 然 ...
- P3588 【[POI2015]PUS】(线段树优化建边)
P3588 [[POI2015]PUS] 终于有个能让我一遍过的题了,写篇题解纪念一下 给定长度为n的序列和其中部分已知的数,还有m个大小关系:区间\([l,r]\)中,有k个给定的数比剩下的\(r- ...
- [POI2015]PUS
嘟嘟嘟 这题只要往正确的方面想,就很简单. 首先,这是一道图论题! 想到这,这题就简单了.对于两个数\(i\)和\(j\),如果\(i\)比\(j\)大,就从\(i\)向\(j\)连边.然后如果图中存 ...
- 洛谷P3588 [POI2015]PUS
题面 sol:说了是线段树优化建图的模板... 就是把一整个区间的点连到一个点上,然后用那个点来连需要连一整个区间的点就可以了,就把边的条数优化成n*log(n)了 #include <queu ...
- 洛谷P3588 [POI2015]PUS(线段树优化建图)
题面 传送门 题解 先考虑暴力怎么做,我们把所有\(r-l+1-k\)中的点向\(x\)连有向边,表示\(x\)必须比它们大,那么如果这张图有环显然就无解了,否则的话我们跑一个多源最短路,每个点的\( ...
- P3588 [POI2015]PUS
好题 思路:线段树优化建图+拓扑DP or 差分约束(都差不多): 提交:3次 错因:眼瞎没看题,Inf写的0x3f3f3f3f 题解: 类似差分约束的模型,\(a<b\rightarrow a ...
- [POI2015]PUS [线段树优化建图]
problem 线段树优化建图,拓扑,没了. #include <bits/stdc++.h> #define ls(x) ch[x][0] #define rs(x) ch[x][1] ...
- POI2015 解题报告
由于博主没有BZOJ权限号, 是在洛咕做的题~ 完成了13题(虽然有一半难题都是看题解的QAQ)剩下的题咕咕咕~~ Luogu3585 [POI2015]PIE Solution 模拟, 按顺序搜索, ...
- Luogu P3783 [SDOI2017]天才黑客
题目大意 一道码量直逼猪国杀的图论+数据结构题.我猪国杀也就一百来行 首先我们要看懂鬼畜的题意,发现其实就是在一个带权有向图上,每条边有一个字符串信息.让你找一个点出发到其它点的最短路径.听起来很简单 ...
随机推荐
- TigerGraph入门
测试机器配置 1G内存,1个核,CentOS Linux release 7.4.1708 (Core)的云主机,一块50G HDD的云主机. 1. 安装 下载了目前最新的开发者版本,下载链接:htt ...
- openstack实验环境搭建
Openstack实验文档 一.base节点 1.1配置网络 vim /etc/sysconfig/network-scripts/ifcfg-eth0 1.2关闭防火墙和selinux system ...
- 题解 P1864 【[NOI2009]二叉查找树】
#include<cstdio> #include<string> #include<cstring> #include<iostream> #incl ...
- Spark学习之第一个程序 WordCount
WordCount程序 求下列文件中使用空格分割之后,单词出现的个数 input.txt java scala python hello world java pyfysf upuptop wintp ...
- codewars[7]-python Friend or Foe?
list中保留四字母的,然后return. 解 def friend(x): i = len(x) ii = [] a = 0 while a < i: if len(x[a]) == 4: i ...
- Winform 连接Web Service 记录
一般自己控制的项目都会使用webApi,比较少使用WS,感觉要配置一堆东西很繁琐. 场景:多个系统间数据交互. 角色:我们属于下游系统,要把一部分数据格式化后上传到SAP中. SAP提供了一个WS,使 ...
- 使用nginx+tomcat实现动静分离
动态资源与静态资源的区别 微微的概括一下 静态资源: 当用户多次访问这个资源,资源的源代码永远不会改变的资源. 动态资源:当用户多次访问这个资源,资源的源代码可能会发送改变. 什么是动静分离 动静分离 ...
- GCC 编译多个文件
今天写数据结构的example,定义了3个文件:lish.h list.c main.c list.h是list.c的头文件,mian.c中对list.h进行了引用.代码如下: list.h 1 #i ...
- mysql协议分析2---认证包
主人看到navicat和mysql在那嘻嘻哈哈,眉来眼去的,好不快乐,忽然也想自己写个程序,直接去访问Mysql,虽然现在已经有很多现成的中间件可以直接拿来用了,程序只要负责写sql语句就行了,但是主 ...
- 计时器(Chronometer)、标签(TabHost)
计时器(Chronometer) 方法 描述 public Chronometer(Context context)[构造方法] 创建Chronometer对象 public long getBase ...