这难道不是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. docker《三》单机部署项目容器,nginx负载均衡

    接着<二> 创建一个网段(和二在一个网段) docker network create --subnet=172.19.0.0/24 pro-net docker run -d --nam ...

  2. promise例题

    let promise = new Promise(resolve => { console.log('Promise'); resolve(); }); promise.then(functi ...

  3. Linux centos7 -bash: pstree: 未找到命令

    2021-08-12 1. 命令简介pstree命令将所有行程以树状图显示,树状图将会以 pid (如果有指定) 或是以 init 这个基本行程为根 (root),如果有指定使用者 id,则树状图会只 ...

  4. 一、Git分布式版本控制系统

    1.引入 在开发一个软件项目时,本地只有几十行代码或几百行代码时还可以维护,但当代码达到一定的数量后或两三个人共同开发一个项目时,就很容易会出现代码混乱.冲突.排错难等问题.一旦开发完工以后发现整个项 ...

  5. MySQL——MySQL初始化配置文件

    初始化配置文件(影响服务器和客户端程序) 1.MySQL初始化配置加载顺序: 命令行 ----> 初始化配置文件 ----> 预编译选项 2.MySQL初始化配置文件加载顺序: (1)/e ...

  6. MapperScannerConfigurer之sqlSessionFactoryBeanName注入方式

    Spring整合Mybatis时,项目启动时报错:(MapperScannerConfigurer之sqlSessionFactoryBeanName注入方式) pringframework.bean ...

  7. JAVA安全基础之代理模式(一)

    JAVA安全基础之代理模式(一) 代理模式是java的一种很常用的设计模式,理解代理模式,在我们进行java代码审计时候是非常有帮助的. 静态代理 代理,或者称为 Proxy ,简单理解就是事情我不用 ...

  8. 马哈鱼数据血缘分析器分析case-when语句

    马哈鱼数据血缘分析器是一个分析数据血缘关系的平台,可以在线直接递交 SQL 语句进行分析,也可以选择连接指定数据库获取 metadata.从本地上传文件目录.或从指定 git 仓库获取脚本进行分析. ...

  9. Expression 表达式动态生成

    http://blog.csdn.net/duan1311/article/details/51769119 以上是拼装和调用GroupBy的方法,是不是很简单,只要传入分组列与合计列就OK了! 下面 ...

  10. CentOS安装oh-my-zsh并配置语法高亮和命令自动补全

    安装zsh 和 oh-my-zsh 安装zsh yum install zsh 安装git yum install git 切换默认shell chsh -s /bin/zsh clone from ...