[BZOJ3128]a+b Problem


题解
最小割+主席树优化建图
首先看到每个点只有\(0/1\)两种状态就想到最小割
然后由于有一个限制是点\(i\)是黑点且有符合条件的白点就会减去\(p_i\)
所以我们将\(S\)集合设为黑点集合,\(T\)集合设为白点集合
然后\(S\to i\)流量为\(b_i\) , \(i\to T\)流量为\(w_i\)
然后我们就需要考虑如果一个点选择了黑点那么就要去判断有没有符合条件的白点
所以我们对每个\(i\)新建一个\(i'\)
然后\(i\to i'\)连流量为\(p_i\)的边
\(i'\)向符合条件的\(j\)连流量为\(INF\)的边
由于是求最大值,所以答案就是\(\sum_{b_i+w_i}-\)最小割
这样建图的最小割就可以起到自动分类讨论的作用
例如如果\(i\)为黑点,\(j\)为白点,那么就会产生\(-p_i\)的贡献
这样的话如果我们实际选择了\(i\)为黑点,\(j\)为白点
那么这一路的流量就是\(w_i+b_j+\min(b_i-w_i,p_i,w_j-b_j)\)
这样就自动的起到了分类讨论的作用
然后我们发现一个黑点对于符合条件的白点的要求是一个二维的限制
所以可以考虑主席树优化建图
跟线段树优化建图比较类似
就是在继承上一棵主席树的时候两棵主席树之间要互相连一条边
void insert() {
t[++tot] = t[now] ;
add_edge(tot , now) ; /*注意这里要连边*/
now = tot ;
}
代码
#include<map>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
# define ls (t[now].lsn)
# define rs (t[now].rsn)
const int M = 500005 ;
const int N = 5050 ;
const int INF = 1e9 ;
using namespace std ;
inline int read() {
char c = getchar() ; int x = 0 , w = 1 ;
while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
return x*w ;
}
map < int , int > mp ;
int n , tot , S , T , cnt ;
int num = 1 , hea[M] , ans ;
int rt[N] , s[N] , suc[N] , idk[N] , d[M] ;
int a[N] , b[N] , w[N] , lp[N] , rp[N] , p[N] ;
struct E { int nxt , to , dis ; } edge[M * 5] ;
struct Node { int lsn , rsn ; } t[M] ;
inline void Insert_edge(int from , int to , int dis) {
edge[++num].nxt = hea[from] ; edge[num].to = to ;
edge[num].dis = dis ; hea[from] = num ;
}
inline void add_edge(int u , int v , int w) {
Insert_edge(u , v , w) ;
Insert_edge(v , u , 0) ;
}
inline int Gid(int x) {
int l = 1 , r = cnt , ret = 0 , mid ;
while(l <= r) {
mid = (l + r) >> 1 ;
if(suc[mid] <= x) l = mid + 1 , ret = mid ;
else r = mid - 1 ;
}
return ret ;
}
void Insert(int id , int x , int l , int r , int &now) {
t[++tot] = t[now] ; add_edge(tot , now , INF) ; now = tot ;
if(l == r) { add_edge(now , id , INF) ; return ; }
int mid = (l + r) >> 1 ;
if(mid >= x) Insert(id , x , l , mid , ls) ;
else Insert(id , x , mid + 1 , r , rs) ;
if(ls) add_edge(now , ls , INF) ;
if(rs) add_edge(now , rs , INF) ;
}
void Add(int id , int L , int R , int l , int r , int now) {
if(now <= n) return ;
if(l >= L && r <= R) { add_edge(id , now , INF) ; return ; }
int mid = (l + r) >> 1 ;
if(mid >= R) Add(id , L , R , l , mid , ls) ;
else if(mid < L) Add(id , L , R , mid + 1 , r , rs) ;
else Add(id , L , mid , l , mid , ls) , Add(id , mid + 1 , R , mid + 1 , r , rs) ;
}
inline bool bfs() {
queue < int > q ; q.push(S) ;
memset(d , 0 , sizeof(d)) ; d[S] = 1 ;
while(!q.empty()) {
int u = q.front() ; q.pop() ;
for(int i = hea[u] ; i ; i = edge[i].nxt) {
int v = edge[i].to ;
if(!d[v] && edge[i].dis > 0) {
d[v] = d[u] + 1 ;
q.push(v) ; if(v == T) return true ;
}
}
}
return d[T] ;
}
int dfs(int u , int dis) {
if(u == T || !dis) return dis ; int sum = 0 ;
for(int i = hea[u] ; i ; i = edge[i].nxt) {
int v = edge[i].to ;
if(d[v] == d[u] + 1 && edge[i].dis > 0) {
int diss = dfs(v , min(dis , edge[i].dis)) ;
if(diss > 0) {
edge[i].dis -= diss ; edge[i ^ 1].dis += diss ;
dis -= diss ; sum += diss ; if(!dis) break ;
}
}
}
if(!sum) d[u] = -1 ; return sum ;
}
inline int dinic() {
int tmp = 0 ;
while(bfs())
tmp += dfs(S , INF) ;
return tmp ;
}
int main() {
n = read() ;
for(int i = 1 ; i <= n ; i ++) {
a[i] = read() ; b[i] = read() ; w[i] = read() ;
lp[i] = read() ; rp[i] = read() ; p[i] = read() ;
add_edge(S , ++tot , b[i]) ;
s[i] = a[i] ; ans += b[i] + w[i] ;
}
rt[0] = tot ;
sort(s + 1 , s + n + 1) ;
for(int i = 1 ; i <= n ; i ++) {
if(i == 1 || s[i] != s[i - 1]) ++ cnt ;
mp[s[i]] = cnt ; suc[cnt] = s[i] ;
}
for(int i = 1 ; i <= n ; i ++)
a[i] = mp[a[i]] ;
for(int i = 1 ; i <= n ; i ++) {
rt[i] = rt[i - 1] ;
Insert(i , a[i] , 0 , cnt , rt[i]) ;
}
for(int i = 1 ; i <= n ; i ++) {
idk[i] = ++ tot ;
add_edge(i , idk[i] , p[i]) ;
}
T = tot + 1 ;
for(int i = 1 ; i <= n ; i ++)
add_edge(i , T , w[i]) ;
suc[0] = -1 ;
for(int i = 1 , l , r ; i <= n ; i ++) {
l = Gid(lp[i]) , r = Gid(rp[i]) ;
if(lp[i] != suc[l]) ++ l ;
if(l > r) continue ;
Add(idk[i] , l , r , 0 , cnt , rt[i - 1]) ;
}
printf("%d\n",ans - dinic()) ;
return 0 ;
}
[BZOJ3128]a+b Problem的更多相关文章
- 1199 Problem B: 大小关系
求有限集传递闭包的 Floyd Warshall 算法(矩阵实现) 其实就三重循环.zzuoj 1199 题 链接 http://acm.zzu.edu.cn:8000/problem.php?id= ...
- No-args constructor for class X does not exist. Register an InstanceCreator with Gson for this type to fix this problem.
Gson解析JSON字符串时出现了下面的错误: No-args constructor for class X does not exist. Register an InstanceCreator ...
- C - NP-Hard Problem(二分图判定-染色法)
C - NP-Hard Problem Crawling in process... Crawling failed Time Limit:2000MS Memory Limit:262144 ...
- Time Consume Problem
I joined the NodeJS online Course three weeks ago, but now I'm late about 2 weeks. I pay the codesch ...
- Programming Contest Problem Types
Programming Contest Problem Types Hal Burch conducted an analysis over spring break of 1999 and ...
- hdu1032 Train Problem II (卡特兰数)
题意: 给你一个数n,表示有n辆火车,编号从1到n,入站,问你有多少种出站的可能. (题于文末) 知识点: ps:百度百科的卡特兰数讲的不错,注意看其参考的博客. 卡特兰数(Catalan):前 ...
- BZOJ2301: [HAOI2011]Problem b[莫比乌斯反演 容斥原理]【学习笔记】
2301: [HAOI2011]Problem b Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 4032 Solved: 1817[Submit] ...
- [LeetCode] Water and Jug Problem 水罐问题
You are given two jugs with capacities x and y litres. There is an infinite amount of water supply a ...
- [LeetCode] The Skyline Problem 天际线问题
A city's skyline is the outer contour of the silhouette formed by all the buildings in that city whe ...
随机推荐
- 对于atomic nonatomic assign retain copy strong weak的简单理解
atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作 1)atomic 设置成员变量的@property属性时,atomic是默认值,提供多线程安全 在多线程环 ...
- undefined reference to '__android_log_print'解决方案
1:在源程序中添加头文件 #include <cutils/log.h> 2:在Android.mk中添加 LOCAL_SHARED_LIBRARIES := \ libutils \ l ...
- CSS动画硬件加速
http://zencode.in/14.CSS%E5%8A%A8%E7%94%BB%E7%9A%84%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96.html http:// ...
- Experimental Educational Round: VolBIT Formulas Blitz K. Indivisibility —— 容斥原理
题目链接:http://codeforces.com/contest/630/problem/K K. Indivisibility time limit per test 0.5 seconds m ...
- U盘安装Ubuntu 14.04 LTS正式版 出现如下的提示,不能继续,如何操作?
I had a problem (minor annoyance) when booting up Arch linux with a USB drive connected. The problem ...
- Partition算法及Partition算法用于快速排序
JavaScript简单方便,所以用JavaScript实现,可以在Chrome控制台下观察运行结果.主要实现Partition算法,比如输入为 var array = [4, 2, 1, 3, ...
- Java深度理解——Java字节代码的操纵
导读:Java作为业界应用最为广泛的语言之一,深得众多软件厂商和开发者的推崇,更是被包括Oracle在内的众多JCP成员积极地推动发展.但是对于 Java语言的深度理解和运用,毕竟是很少会有人涉及的话 ...
- TCP连接过程
TCP建立连接与释放连接 最近复习准备<计算机网络>考试,感觉TCP协议建立连接与释放连接这两个过程比较重要,所以把自己理解的部分写下来. 1.建立连接:(三次握手) (1)客户端发 ...
- bootstrap学习大纲
bootstrap 学习分三部分,分别是 css样式,css组件,js插件. 下面介绍三部分分别要学习的内容: 1.css样式:栅格系统,排版,代码,表格,表单,按钮,图片,辅助类,响应式工具. 2. ...
- 如何更快更好的写出cnblog博客?windows live writer推荐
之前总是会羡慕网上那些技术牛人的博客都写的那么给力,后来一搜发现还是有工具可用的. 这里就推荐一款写博客的"神器",Windows Live Writer (Get It Now! ...