【UOJ#77】A+B Problem

1|0题目


题目链接:https://uoj.ac/problem/77
题目名称是吸引你点进来的。
从前有个 n 个方格排成一行,从左至右依此编号为 1,2,,n
有一天思考熊想给这 n 个方格染上黑白两色。
i 个方格上有 6 个属性:ai,bi,wi,li,ri,pi
如果方格 i 染成黑色就会获得 bi 的好看度。
如果方格 i 染成白色就会获得 wi 的好看度。
但是太多了黑色就不好看了。如果方格 i 是黑色,并且存在一个 j 使得 1j<iliajri 且方格 j 为白色,那么方格 i 就被称为奇怪的方格。
如果方格 i 是奇怪的方格,就会使总好看度减少 pi
也就是说对于一个染色方案,好看度为:

方格i为黑色bi+方格i为白色wi方格i为奇怪的方格pi

现在给你 n,a,b,w,l,r,p,问所有染色方案中最大的好看度是多少。
n5000,a,l,r109,v2×105,p3×105

2|0思路


经典题。不过感觉十分缝合。
考虑没有黑白格子之间的限制怎么做。由于答案等价于所有格子黑白价值之和减去不选的颜色的价值之和,可以考虑网络流,源点连向每一个格子连一条流量为 bi 的边,每一个格子向汇点连一条流量为 wi 的边,然后跑最小割即可。
话说为什么不直接在黑格子和白格子权值中取个最大值啊。
现在有了黑白格子之间的限制,就把每一个点拆成两个点,第一个点依然先按上述方式连边,然后每一个点的一号点向二号点连一条流量为 pi 的边。二号点再向所有 j<iliajri 的格子的一号点连边,边权为 +
这样的话,一个格子要么切断黑边(选择白色);要么切断白边和一二号点之间的边(黑色,奇怪的方格);要么切断白边和所有二号点连向的点的白边(黑色,所影响的格子均为黑色)。显然是满足要求的。
但是这样建边的话,边数显然是 O(n2) 的。由于每一个点是向一个区间的点连边,所以上线段树优化建图即可。
但是还有一个要求是每一个二号点只能向编号小于自己的点连边,所以还要套上一个可持久化。最终主席树 + 最小割即可。
时间复杂度 O(n3logn),空间复杂度 O(nlogn)

3|0代码


人傻常熟巨大,交了三发只过了一发。。。

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=120010,Inf=1e9; const ll InfLL=7e18; int head[N],rt[N],a[N],b[N],w[N],p[N],L[N],R[N],cur[N],dep[N],pre[N]; int n,S,T,tot=1; ll maxf,sumf,c[N]; struct edge { int next,to; ll flow; }e[N*20]; void add(int from,int to,ll flow) { e[++tot]=(edge){head[from],to,flow}; head[from]=tot; e[++tot]=(edge){head[to],from,0}; head[to]=tot; } struct SegTree { int tot,lc[N*4],rc[N*4]; int build(int l,int r) { int x=++tot; if (l==r) return x; int mid=(l+r)>>1; lc[x]=build(l,mid); rc[x]=build(mid+1,r); add(x+2*n,lc[x]+2*n,InfLL); add(x+2*n,rc[x]+2*n,InfLL); return x; } void adde(int x,int l,int r,int ql,int qr,int u) { if (ql<=l && r<=qr) { add(u+n,x+2*n,InfLL); return; } int mid=(l+r)>>1; if (ql<=mid) adde(lc[x],l,mid,ql,qr,u); if (qr>mid) adde(rc[x],mid+1,r,ql,qr,u); } int update(int now,int l,int r,int k,int u) { int x=++tot; lc[x]=lc[now]; rc[x]=rc[now]; if (l==k && r==k) { add(x+2*n,u,InfLL); return x; } int mid=(l+r)>>1; if (k<=mid) lc[x]=update(lc[now],l,mid,k,u); else rc[x]=update(rc[now],mid+1,r,k,u); add(x+2*n,lc[x]+2*n,InfLL); add(x+2*n,rc[x]+2*n,InfLL); return x; } }seg; bool bfs() { memcpy(cur,head,sizeof(head)); memset(dep,0x3f3f3f3f,sizeof(dep)); queue<int> q; q.push(S); dep[S]=0; while (q.size()) { int u=q.front(); q.pop(); for (int i=head[u];~i;i=e[i].next) { int v=e[i].to; if (e[i].flow && dep[v]>dep[u]+1) { dep[v]=dep[u]+1; pre[u]=v; q.push(v); } } } return dep[T]<Inf; } ll dfs(int x,ll flow) { if (x==T) return flow; ll used=0,res; for (int i=cur[x];~i;i=e[i].next) { int v=e[i].to; cur[x]=i; if (e[i].flow && dep[v]==dep[x]+1) { res=dfs(v,min(e[i].flow,flow-used)); used+=res; e[i].flow-=res; e[i^1].flow+=res; if (used==flow) return used; } } return used; } void dinic() { while (bfs()) maxf+=dfs(S,InfLL); } int main() { memset(head,-1,sizeof(head)); S=N-1; T=N-2; scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d%d%d%d%d%d",&a[i],&b[i],&w[i],&L[i],&R[i],&p[i]); add(S,i,b[i]); add(i,T,w[i]); add(i,i+n,p[i]); sumf+=b[i]+w[i]; c[i]=1LL*a[i]*Inf+i; } sort(c+1,c+1+n); int cnt=unique(c+1,c+1+n)-c-1; c[++cnt]=InfLL; rt[0]=seg.build(1,n); for (int i=1;i<=n;i++) { a[i]=lower_bound(c+1,c+1+cnt,1LL*Inf*a[i]+i)-c; L[i]=lower_bound(c+1,c+1+cnt,1LL*Inf*L[i])-c; R[i]=lower_bound(c+1,c+1+cnt,1LL*Inf*(R[i]+1))-c-1; if (L[i]<=R[i]) seg.adde(rt[i-1],1,n,L[i],R[i],i); rt[i]=seg.update(rt[i-1],1,n,a[i],i); } dinic(); printf("%lld\n",sumf-maxf); return 0; }

__EOF__

本文作者stoorz
本文链接https://www.cnblogs.com/stoorz/p/14223752.html
关于博主:菜死了 /fad
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   stoorz  阅读(173)  评论(1编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示