[Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)
[Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)
题面
有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i> out_j\),那么j就可以套在i里面。现在我们要选出n个物品的一个子集,这个子集内的k个物品全部套在一起,且剩下的物品都无法添加到这个子集中(没有空间塞进去)。定义浪费的空间为子集中空心的部分,即\(in_{i_1} + (in_{i_2} - out_{i_1}) + (in_{i_3} - out_{i_2}) + \dots + (in_{i_k} - out_{i_{k-1}})\)。求浪费空间最少的子集个数。
分析
(CF的官方题解为)
考虑建图,对于每个物品i,我们找到能套到i中的物品j,从i向j连一条边,边权为\(in_i-out_j\)。最后如果某个点入度为0,就从虚拟节点s向它连一条边权为0的边,出度为0就向虚拟节点t连一条边权为\(in_i\)的边。这样我们就得到了一个有向无环图。可以发现,DAG上s到t的每一条路径都对应着满足条件的一个子集,而路径的边权和就是子集浪费的空间。那么问题就转化为,求DAG上s到t的最短路径条数
首先直接建图复杂度\(O(n^2)\)肯定是会TLE的。发现如果把物品按\(out_i\)从小到大排序,那么可以连边的物品是一个连续区间[1,R],R可以二分查找求出。可以用线段树优化建图。
我们将线段树看成一个有向图,每个线段树节点看成图上的一个点,[l,r]向[l,mid],[mid+1,r]连边,叶子节点[l,l]向原图上的节点l连边。对于从x向编号属于区间[L,R]的点连边,我们用类似线段树区间更新的方法,将[L,R]拆成许多个小区间,再直接向这些小区间暴力连边。
边权的问题如何解决?我们把边权\(in_i-out_j\)拆成两部分,叶子节点[l,l]向原图上的节点l连边权为\(-out_l\)的边,x向拆出来的边连边权为\(in_x\)的边。
最短路径数也很容易解决。记\(dist[x]\)表示s到x的最短路,\(cnt[x]\)表示s到x的最短路条数。初始时\(dist[s]=0,cnt[s]=1\),其他点\(dist[x]= +∞ ,cnt[x]=0 (x \neq s)\)
我们先对DAG拓扑排序,然后按照拓扑序,对每个节点x松弛它的出边,即若\(dist[y]>dist[x]+w(x,y)\),就更新dist[y]。由于拓扑排序过,x会在y之前被更新,不会出现顺序问题。
然后类似的进行路径计数,求完最短路长度后,按照拓扑序对每个节点x做DP,如果\(dist[y]=dist[x]+w(x,y)\),那么\(cnt[y]+=cnt[x]\),最后的答案为\(cnt[t]\)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxn 1000000
#define maxm 3000000
#define mod 1000000007
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int n,new_n;
struct item{
int in;
int out;
item(){
}
item(int _in,int _out){
in=_in;
out=_out;
}
friend bool operator < (item p,item q){
if(p.out==q.out) return p.in<q.in;
return p.out<q.out;
}
}a[maxn+5];
int tmp[maxn+5];
struct edge{
int from;
int to;
int len;
int next;
}E[maxm*2+5];
int head[maxn+5];
int in[maxn+5];
int sz=1;
void add_edge(int u,int v,int w){
// printf("%d->%d cost=%d\n",u,v,w);
sz++;
E[sz].from=u;
E[sz].to=v;
E[sz].len=w;
E[sz].next=head[u];
head[u]=sz;
in[v]++;
}
ll dist[maxn+5];
ll cnt[maxn+5];
int seq[maxn+5];
void topo_sort(int s,int t){
int len=0;
queue<int>q;
for(int i=s;i<=t;i++){
if(!in[i]) q.push(i);
}
memset(dist,0x3f,sizeof(dist));
dist[s]=0;
while(!q.empty()){
int x=q.front();
q.pop();
seq[++len]=x;
for(int i=head[x];i;i=E[i].next){
int y=E[i].to;
in[y]--;
if(!in[y]) q.push(y);
}
}
for(int i=1;i<=len;i++){
int x=seq[i];
for(int i=head[x];i;i=E[i].next){
int y=E[i].to;
if(dist[y]>dist[x]+E[i].len) dist[y]=dist[x]+E[i].len;
}
}
memset(cnt,0,sizeof(cnt));
cnt[s]=1;
for(int i=1;i<=len;i++){
int x=seq[i];
for(int i=head[x];i;i=E[i].next){
int y=E[i].to;
if(dist[y]==dist[x]+E[i].len){
cnt[y]+=cnt[x];
cnt[y]%=mod;
}
}
}
}
struct segment_tree{
struct tree_node{
int l;
int r;
}tree[maxn*4+5];
void build(int l,int r,int pos){
tree[pos].l=l;
tree[pos].r=r;
if(l==r){
new_n=max(new_n,pos+n);
add_edge(pos+n,l,-a[l].out);
return;
}
int mid=(l+r)>>1;
add_edge(pos+n,(pos<<1)+n,0);
add_edge(pos+n,(pos<<1|1)+n,0);
build(l,mid,pos<<1);
build(mid+1,r,pos<<1|1);
}
void update(int L,int R,int ux,int uv,int pos){
if(L<=tree[pos].l&&R>=tree[pos].r){
add_edge(ux,pos+n,uv);
return;
}
int mid=(tree[pos].l+tree[pos].r)>>1;
if(L<=mid) update(L,R,ux,uv,pos<<1);
if(R>mid) update(L,R,ux,uv,pos<<1|1);
}
}T;
ll cov[maxn+5];//统计每个节点可以被套的次数,如果cov[i]=0,则由s向i连边
int main(){
scanf("%d",&n);
new_n=0;
new_n+=n;
for(int i=1;i<=n;i++){
scanf("%d %d",&a[i].out,&a[i].in);
tmp[i]=a[i].out;
}
sort(a+1,a+1+n);
sort(tmp+1,tmp+1+n);
T.build(1,n,1);
int s=0,t=new_n+1;
for(int i=1;i<=n;i++){
int rb=upper_bound(tmp+1,tmp+1+n,a[i].in)-tmp-1;
if(rb>=1){
cov[1]++;//差分统计,相当于[1,rb]+1
cov[rb+1]--;
T.update(1,rb,i,a[i].in,1);
}else{
add_edge(i,t,a[i].in);
}
}
for(int i=1;i<=n;i++){
cov[i]+=cov[i-1];
if(cov[i]==0) add_edge(s,i,0);
}
topo_sort(s,t);
printf("%I64d\n",cnt[t]);
}
[Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)的更多相关文章
- CodeForces 786B Legacy(线段树优化建图+最短路)
[题目链接] http://codeforces.com/problemset/problem/786/B [题目大意] 给出一些星球,现在有一些传送枪,可以从一个星球到另一个星球, 从一个星球到另一 ...
- Codeforces 786B Legacy(线段树优化建图)
题目链接 Legacy 首先对于输入的$n$,建立一棵线段树. 显然线段树有大概$2n$个结点,每个节点对应一段区间 我们把这$2n$个结点加入我们的无向图中,一起跑最短路. 具体连边方案: 我们把 ...
- BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan
Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...
- 【ARC069F】Flags 2-sat+线段树优化建图+二分
Description 数轴上有 n 个旗子,第 ii 个可以插在坐标 xi或者 yi,最大化两两旗子之间的最小距离. Input 第一行一个整数 N. 接下来 N 行每行两个整数 xi, ...
- CF786B Legacy 线段树优化建图 + spfa
CodeForces 786B Rick和他的同事们做出了一种新的带放射性的婴儿食品(???根据图片和原文的确如此...),与此同时很多坏人正追赶着他们.因此Rick想在坏人们捉到他之前把他的遗产留给 ...
- G. 神圣的 F2 连接着我们 线段树优化建图+最短路
这个题目和之前写的一个线段树优化建图是一样的. B - Legacy CodeForces - 787D 线段树优化建图+dij最短路 基本套路 之前这个题目可以相当于一个模板,直接套用就可以了. 不 ...
- 【BZOJ3681】Arietta 树链剖分+可持久化线段树优化建图+网络流
[BZOJ3681]Arietta Description Arietta 的命运与她的妹妹不同,在她的妹妹已经走进学院的时候,她仍然留在山村中.但是她从未停止过和恋人 Velding 的书信往来.一 ...
- 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序
题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆. 现在 ...
- 【bzoj4699】树上的最短路(树剖+线段树优化建图)
题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...
随机推荐
- DUBBO原理、应用与面经总结
研读dubbo源码已经有一段时间了,dubbo中有非常多优秀的设计模式和示例代码值得学习,但是dubbo的调用层级和方法链都较为繁杂,如果不对源码思路进行梳理则很容易忘却,因此总结一篇研读心得,从阅读 ...
- 【UOJ#207】共价大爷游长沙
题目链接 题目描述 火车司机出秦川,跳蚤国王下江南,共价大爷游长沙.每个周末,勤劳的共价大爷都会开车游历长沙市. 长沙市的交通线路可以抽象成为一个 \(n\) 个点 \(n−1\) 条边的无向图,点编 ...
- HTTP教程
适合人群 本教程已为计算机学科毕业生和Web开发人员准备,帮助他们了解与超文本传输协议(HTTP)相关的基本到高级概念. 预备知识 在继续本教程之前,最好对Web概念,Web浏览器,Web服务器, ...
- LTM_本地流量管理(二)
会话保持 首先要熟悉两个概念:连接connect和会话session 连接:在四层负载均衡中,连接是最小元素. l 源端口:客户端随机产生的端口. l 源地址:发起请求的源IP地址. l 目的端 ...
- 面试题常考&必考之--js数组排序冒泡排序和快速排序
冒泡排序: 原理:比较相邻的元素,将值大的元素交换到右边.(如果相等不进行交换) 实例: 要排列数组:[10,1,35,61,89,36,55] 第一趟排序: 第1次排序:10和1比较,10>1 ...
- Wannafly挑战赛16 #E 弹球弹弹弹 splay+基环树+各种思维
链接:https://ac.nowcoder.com/acm/problem/16033来源:牛客网 有n个位置,标号为1到n的整数,m次操作,第i次操作放置一个弹球在b[i] xor c[i-1]处 ...
- HDU 3613 Best Reward ( 拓展KMP求回文串 || Manacher )
题意 : 给个字符串S,要把S分成两段T1,T2,每个字母都有一个对应的价值,如果T1,T2是回文串,那么他们就会有一个价值,这个价值是这个串的所有字母价值之和,如果不是回文串,那么这串价值就为0.问 ...
- luogu P1028 数的计算 x
P1028 数的计算 题目描述 我们要求找出具有下列性质数的个数(包含输入的自然数n): 先输入一个自然数n(n<=1000),然后对此自然数按照如下方法进行处理: 1.不作任何处理; 2.在它 ...
- Internet History, Technology, and Security(week7)——Technology: Application Protocols
Layer 4: Applications Application Layer TCP提供了“a reliable pipe”(一个坚固的水管)连接用户和服务器,确保了数据能准确不出意外地传输,所以A ...
- SQL Server DACPAC数据库部署错误
DACPAC使用sqlpackage.exe进行部署,部署时候报错: EXEC : error SQL72035: [dbo].[table] is under change data capture ...