这难道不是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. ES6——静态属性与静态方法

    静态方法只能写在class内,constructor外.通过static关键字声明 静态属性只能写在class外,通过 类名.属性名 = 属性值 声明 //静态属性与静态方法(ES6明确规定,Clas ...

  2. 用CUDA写出比Numpy更快的规约求和函数

    技术背景 在前面的几篇博客中我们介绍了在Python中使用Numba来写CUDA程序的一些基本操作和方法,并且展示了GPU加速的实际效果.在可并行化的算法中,比如计算两个矢量的加和,或者是在分子动力学 ...

  3. ks.cfg文件相关

    原文转自:https://www.cnblogs.com/itzgr/p/10029631.html作者:木二 目录 一 图形化生成ks.cfg文件 二 ks.cfg文件相关项解析 一 图形化生成ks ...

  4. CentOS 7.3安装Zabbix3.2

    一.ZABBIX概述 Zabbix是一个基于Web界面的分布式系统监控的企业级开源软件.可以监视各种系统与设备的参数,保障服务器及设备的安全运营.   Zabbix的功能和特性: 1.安装与配置简单: ...

  5. 手把手教你在 SuperEdge 上用 EdgeX Foundry 接入 IoT 设备

    作者 连泓乔,华南理工计算机科学与技术大三在读,主要研究容器领域,Kubernetes.容器等云原生技术爱好者,SuperEdge 优秀贡献者. 王冬,腾讯云研发工程师,专注于 Kubernetes. ...

  6. MongoDB 常见问题 - 解决 brew services list 查看 MongoDB 服务 status 显示 error 的问题

    问题背景 将 MongoDB 作为服务运行 brew services start mongodb-community@4.4 也显示运行成功了,但是查看服务列表的时候,发现 MongoDB 服务的还 ...

  7. API:获取当前用户的公网IP

    在vue项目根目录下" public " 文件夹中的index.html,也就是根节点所在的文件引入JS,vue项目中静态文件需要在这里引入,用 script 标签规避跨域 < ...

  8. JS004. 获取数组最后一个元素且不改变数组的四种方法

    TAG: Array.length Array.prototype.reverse() Array.prototype.slice() Array.prototype.pop() Array对象 - ...

  9. 如何实现 iOS 短视频跨页面的无痕续播?

    在一切皆可视频化的今天,短视频内容作为移动端产品新的促活点,受到了越来越多的重视与投入.盒马在秒播.卡顿率.播放成功率等基础优化之外,在用户使用体验上引入了无痕续播能力,提升用户观看视频内容的延续性. ...

  10. Devexpress 饼状图

    <dxc:ChartControl Name="chart"                                BorderThickness="0&q ...