这难道不是happiness的翻版题嘛?

从\(S\)向一个点连染成白色的收益

从这个点向\(T\)连染成黑色的收益

对于额外的收益,建一个辅助点,跟区间内的每个点连\(inf\),然后向S/T,连流量为收益

这不就结束了吗?

自信写完,提交

woc!!只有40分?

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue> using namespace std; inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
} const int maxn = 100010;
const int maxm = 2e6+1e2;
const int inf = 2e9; int point[maxn],nxt[maxm],to[maxm],val[maxm];
int h[maxn],cnt=1;
int n,m;
int a[maxn],b[maxn];
int s,t;
queue<int> q;
int ans; void addedge(int x,int y,int w)
{
nxt[++cnt]=point[x];
to[cnt]=y;
val[cnt]=w;
point[x]=cnt;
} void insert(int x,int y,int w)
{
addedge(x,y,w);
addedge(y,x,0);
} bool bfs(int s)
{
memset(h,-1,sizeof(h));
h[s]=0;
q.push(s);
while (!q.empty())
{
int x = q.front();
q.pop();
for(int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (val[i]>0 && h[p]==-1)
{
h[p]=h[x]+1;
q.push(p);
}
}
}
if (h[t]==-1) return false;
else return true;
} int dfs(int x,int low)
{
if (x==t || low==0) return low;
int totflow=0;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (val[i]>0 && h[p]==h[x]+1)
{
int tmp = dfs(p,min(low,val[i]));
val[i]-=tmp;
val[i^1]+=tmp;
low-=tmp;
totflow+=tmp;
if (low==0) return totflow;
}
}
if (low>0) h[x]=-1;
return totflow;
} int dinic()
{
int ans=0;
while (bfs(s))
{
ans=ans+dfs(s,inf);
}
return ans;
} void build()
{
s=n+m+100;
t=s+1;
for (int i=1;i<=n;i++)
{
if (a[i]>=0 && b[i]>=0)
{
insert(s,i,a[i]);
insert(i,t,b[i]);
}
if (a[i]<0 && b[i]>=0)
{
insert(i,t,abs(a[i])+b[i]);
}
if (a[i]>=0 && b[i]<0)
{
insert(s,i,abs(b[i])+a[i]);
}
if (a[i]<0 && b[i]<0)
{
insert(s,i,abs(b[i]));
insert(i,t,abs(a[i]));
}
if (a[i]>=0) ans+=a[i];
if (b[i]>=0) ans+=b[i];
}
}
int main()
{
freopen("nicai.in","r",stdin);
freopen("nicai.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) a[i]=read();
for (int i=1;i<=n;i++) b[i]=read();
build();
int num = n+1;
for (int i=1;i<=m;i++)
{
int opt,x,y,z;
opt=read();
x=read();
y=read();
z=read();
if (opt==1)
{
for (int j=x;j<=y;j++)
{
insert(num,j,inf);
}
insert(s,num,z);
num++;
}
else
{
for (int j=x;j<=y;j++)
{
insert(j,num,inf);
}
insert(num,t,z);
num++;
}
ans=ans+z;
}
cout<<ans-dinic()<<endl;
//cout<<dinic()<<endl;
return 0;
}

后来仔细一想。

这么建图的复杂度,简直爆炸呀

不过貌似一段区间同时向一个点连边,这个东西可以优化呀?

哎?好像可以线段树???

这时候就需要我们这个题的重头戏了

线段树优化建图!

线段树优化建图主要是对于一系列一段连续区间向某一个点连边的题。

他的大致思路是

将线段树的节点作为图的点,然后连边的时候,将区间拆成\(log\)个小区间来连边,这样能大大减少边数。然后线段树节点之间的点连边\(inf\),用来确定最小割不会割掉这条边

而一般对于网络流或者双向边的题,一般是需要两颗线段树。

对于这道题,因为是新建的点,需要向\(S/T\)连边

所以需要两颗线段树,但是要注意父亲节点和儿子节点连边的方向

然后对于\(leaf\)节点,我们需要单独记录,并按照上面朴素做法的建图方式建图,然后跑最小割即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue> using namespace std; inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
} const int maxn = 2e5+1e2;
const int maxm = 4e6;
const int inf = 1e9; int f[8*maxn],g[8*maxn];
int point[maxn],nxt[maxm],to[maxm];
int h[maxn],cnt=1,val[maxm];
int n,m;
int s,t;
int leaf[maxn];
long long ymh=0;
int tmp=1 ;
queue<int> q; void addedge(int x,int y,int w)
{
nxt[++cnt]=point[x];
to[cnt]=y;
val[cnt]=w;
point[x]=cnt;
} void insert(int x,int y,int w)
{
addedge(x,y,w);
addedge(y,x,0);
} void build(int root,int l,int r)
{
if (l==r)
{
leaf[l]=++tmp;
f[root]=tmp;
return;
}
int mid = (l+r) >> 1;
f[root]=++tmp;
build(2*root,l,mid);
build(2*root+1,mid+1,r);
insert(f[root],f[2*root],inf);
insert(f[root],f[2*root+1],inf);
} void build1(int root,int l,int r)
{
if (l==r)
{
g[root]=leaf[l];
return;
}
int mid = (l+r) >> 1;
g[root]=++tmp;
build1(2*root,l,mid);
build1(2*root+1,mid+1,r);
insert(g[2*root],g[root],inf);
insert(g[2*root+1],g[root],inf);
} void update(int root,int l,int r,int x,int y,int p)
{
if (x<=l && r<=y)
{
insert(p,f[root],inf);
return;
}
int mid =(l+r) >> 1;
if (x<=mid) update(2*root,l,mid,x,y,p);
if (y>mid) update(2*root+1,mid+1,r,x,y,p);
} void update1(int root,int l,int r,int x,int y,int p)
{
if (x<=l && r<=y)
{
insert(g[root],p,inf);
return;
}
int mid =(l+r) >> 1;
if (x<=mid) update1(2*root,l,mid,x,y,p);
if (y>mid) update1(2*root+1,mid+1,r,x,y,p);
} bool bfs(int s)
{
memset(h,-1,sizeof(h));
h[s]=0;
q.push(s);
while (!q.empty())
{
int x = q.front();
q.pop();
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (val[i]>0 && h[p]==-1)
{
h[p]=h[x]+1;
q.push(p);
}
}
}
//cout<<1<<endl;
if (h[t]==-1) return false;
else return true;
} int dfs(int x,int low)
{
if (x==t || low==0) return low;
int totflow=0;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (val[i]>0 && h[p]==h[x]+1)
{
int tmp = dfs(p,min(low,val[i]));
low-=tmp;
totflow+=tmp;
val[i]-=tmp;
val[i^1]+=tmp;
if (low==0) return totflow;
}
}
if (low>0) h[x]=-1;
return totflow;
} int dinic()
{
int ans=0;
while (bfs(s))
{
ans=ans+dfs(s,inf);
}
return ans;
} int b[maxn],w[maxn];
int main()
{
freopen("nicai.in","r",stdin);
freopen("nicai.out","w",stdout);
n=read(),m=read();
build(1,1,n);
build1(1,1,n);
s=maxn-100;
t=s+1;
for (int i=1;i<=n;i++) b[i]=read();
for (int i=1;i<=n;i++) w[i]=read();
for (int i=1;i<=n;i++)
{
if (b[i]>=0) insert(s,leaf[i],b[i]);
else insert(leaf[i],t,-b[i]);
}
for (int i=1;i<=n;i++)
{
if (w[i]>=0) insert(leaf[i],t,w[i]);
else insert(s,leaf[i],-w[i]);
}
for (int i=1;i<=n;i++)
{
if (b[i]>0) ymh=ymh+b[i];
if (w[i]>0) ymh=ymh+w[i];
}
for (int i=1;i<=m;i++)
{
int l,r,opt,x;
opt=read();
l=read();
r=read();
x=read();
++tmp;
if (opt==1)
{
insert(s,tmp,x);
update(1,1,n,l,r,tmp);
}
if (opt==2)
{
insert(tmp,t,x);
update1(1,1,n,l,r,tmp);
}
ymh+=x;
}
//cout<<ymh<<endl;
cout<<ymh-dinic();
return 0;
}

一个神秘的oj2587 你猜是不是dp(线段树优化建图)的更多相关文章

  1. [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)

    [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...

  2. BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan

    Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...

  3. 【BZOJ3681】Arietta 树链剖分+可持久化线段树优化建图+网络流

    [BZOJ3681]Arietta Description Arietta 的命运与她的妹妹不同,在她的妹妹已经走进学院的时候,她仍然留在山村中.但是她从未停止过和恋人 Velding 的书信往来.一 ...

  4. 【ARC069F】Flags 2-sat+线段树优化建图+二分

    Description ​ 数轴上有 n 个旗子,第 ii 个可以插在坐标 xi或者 yi,最大化两两旗子之间的最小距离. Input ​ 第一行一个整数 N. ​ 接下来 N 行每行两个整数 xi, ...

  5. 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序

    题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足:  Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆.  现在 ...

  6. 【bzoj4699】树上的最短路(树剖+线段树优化建图)

    题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...

  7. 【BZOJ4276】[ONTAK2015]Bajtman i Okrągły Robin 线段树优化建图+费用流

    [BZOJ4276][ONTAK2015]Bajtman i Okrągły Robin Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2 ...

  8. 【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra

    题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a, ...

  9. 【bzoj4383】[POI2015]Pustynia 线段树优化建图+差分约束系统+拓扑排序

    题目描述 给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r,k以及接下来k个正整数,表示a[l],a[l+1],...,a[r- ...

随机推荐

  1. deepin-terminal改造风云再起

    1. 创作背景 使用deepin-terminal的时候,我发现一些小的问题. 在论坛的帖子(https://bbs.deepin.org/zh/post/224502)也总结反馈了这些问题 终端标签 ...

  2. 神舟G7-CT7NK 安装tensorflow-gpu

    参考https://www.cnblogs.com/xbit/p/9768238.html 直接安装,运行keras mnist数字识别报错: Could not create cudnn handl ...

  3. 阿里云服务器部署mongodb

    在阿里云上买了个服务器,部署mongodb遇到一些坑,解决办法也是从网上搜集而来,把零零碎碎的整理记录一下. 服务器是:Alibaba Cloud Linux 下载安装 mongodb官网下载实在是太 ...

  4. C#多线程开发-线程基础 01

    最近由于工作的需要,一直在使用C#的多线程进行开发,其中也遇到了很多问题,但也都解决了.后来发觉自己对于线程的知识和运用不是很熟悉,所以将利用几篇文章来系统性的学习汇总下C#中的多线程开发. 线程基础 ...

  5. python 逆序按行读取文件

    How to read a file in reverse order? import os def readlines_reverse(filename): with open(filename) ...

  6. Python中正则表达式简介

    目录 一.什么是正则表达式 二.正则表达式的基础知识 1. 原子 1)普通字符作为原子 2)非打印字符作为原子 3) 通用字符作为原子 4) 原子表 2. 元字符 1)任意匹配元字符 2)边界限制元字 ...

  7. 手把手教你 Docker Compose的安装和使用

    一.Docker Compose是什么? Docker Compose是一个工具,用于定义和运行多容器应用程序的工具: Docker Compose通过yml文件定义多容器的docker应用: Doc ...

  8. 一文了解Promise使用与实现

    前言 Promise 作为一个前端必备技能,不管是从项目应用还是面试,都应该对其有所了解与使用. 常常遇到的面试五连问: 说说你对 Promise 理解? Promise 的出现解决了什么问题? Pr ...

  9. 1004. 最大连续1的个数 III

    1004. 最大连续1的个数 III 给定一个由若干 0 和 1 组成的数组 A,我们最多可以将 K 个值从 0 变成 1 . 返回仅包含 1 的最长(连续)子数组的长度. 示例 1: 输入:A = ...

  10. CF643F-Bears and Juice【组合数学】

    正题 题目链接:https://www.luogu.com.cn/problem/CF643F 题目大意 题目有点奇怪就直接放翻译了 有 \(n\) 只熊和若干桶果汁和恰好一桶酒,每一天每只熊会选择一 ...