Codeforces 793G - Oleg and chess(网络流+优化建图)

很 trivial 的一道题,评到 3400 非常不理解。

首先一眼二分图匹配,关键点在于建图。显然需要数据结构优化,关键是怎么个优化法,很 trivial 的想法是考虑每一行,将极长的白格对应的连边用线段树优化掉,但是这样显然是不行的,因为一个黑白交错的图就可以把它卡成 n2

考虑借鉴二维矩形扫描线的思想。做二维矩形问题应用很多的一个思想是“继承”,也就是说我们从上到下扫过去的过程,相当于每次给一个区间覆盖次数 +1 或者 -1,这样均摊是 O(1),而在线段树上进行区间操作的时候,大部分节点被覆盖和不被覆盖的状态是不变的,因此考虑类似于动态开点的思想,每次对一个区间进行操作的时候,就新建一个这个节点的版本,如果并考虑左右儿子,如果它们上面没有 tag 就向它们连边,然后叶子节点对应的点则是二分图右部每个点,这样点数显然是 nlogn 的,苟一波最大流就能过了。

实现可以看代码:

const int MAXN=1e4;
const int MAXV=1e6+2;
const int MAXE=1e7;
const int INF=0x3f3f3f3f;
int n,m;vector<tuple<int,int,int> >vec[MAXN+5];
namespace Maxflow{
int S=1000001,T=1000002,hd[MAXV+5],to[MAXE+5],nxt[MAXE+5],cap[MAXE+5],ec=1;
void adde(int u,int v,int f){
to[++ec]=v;cap[ec]=f;nxt[ec]=hd[u];hd[u]=ec;
to[++ec]=u;cap[ec]=0;nxt[ec]=hd[v];hd[v]=ec;
}
int dep[MAXV+5],now[MAXV+5];
bool getdep(){
memset(dep,-1,sizeof(dep));queue<int>q;dep[S]=0;q.push(S);
while(!q.empty()){
int x=q.front();q.pop();now[x]=hd[x];
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=cap[e];
if(z&&!~dep[y])dep[y]=dep[x]+1,q.push(y);
}
}return ~dep[T];
}
int getflow(int x,int f){
if(x==T)return f;int ret=0;
for(int &e=now[x];e;e=nxt[e]){
int y=to[e],z=cap[e];
if(z&&dep[y]==dep[x]+1){
int w=getflow(y,min(f-ret,z));
cap[e]-=w;cap[e^1]+=w;ret+=w;
if(f==ret)return ret;
}
}return ret;
}
int dinic(){
int ret=0;
while(getdep())ret+=getflow(S,INF);
return ret;
}
}using namespace Maxflow;
int ncnt,id[MAXN*4+5],tag[MAXN*4+5];
void pushup(int k){
id[k]=++ncnt;
if(!tag[k<<1])adde(id[k],id[k<<1],INF);
if(!tag[k<<1|1])adde(id[k],id[k<<1|1],INF);
}
void build(int k,int l,int r){
if(l==r)return id[k]=l+n,void();int mid=l+r>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k);
}
void modify(int k,int l,int r,int ql,int qr,int v){
if(ql<=l&&r<=qr)return tag[k]+=v,void();
int mid=l+r>>1;
if(qr<=mid)modify(k<<1,l,mid,ql,qr,v);
else if(ql>mid)modify(k<<1|1,mid+1,r,ql,qr,v);
else modify(k<<1,l,mid,ql,mid,v),modify(k<<1|1,mid+1,r,mid+1,qr,v);
pushup(k);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,x1,y1,x2,y2;i<=m;i++){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
vec[x1].pb(mt(y1,y2,1));vec[x2+1].pb(mt(y1,y2,-1));
}
for(int i=1;i<=n;i++)adde(S,i,1),adde(i+n,T,1);
ncnt=n<<1;build(1,1,n);
for(int i=1;i<=n;i++){
for(auto t:vec[i])
modify(1,1,n,get<0>(t),get<1>(t),get<2>(t));
if(!tag[1])adde(i,id[1],INF);
}printf("%d\n",dinic());
return 0;
}
posted @   tzc_wk  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
历史上的今天:
2021-04-18 洛谷 P5331 - [SNOI2019]通信(CDQ 分治优化建图+费用流)
2021-04-18 Codeforces 1299D - Around the World(线性基+图论+dp)
2021-04-18 洛谷 P3270 - [JLOI2016]成绩比较(容斥原理+组合数学+拉格朗日插值)
2020-04-18 洛谷 P3215 [HNOI2011]括号修复 / [JSOI2011]括号序列(fhq-treap)
2020-04-18 关于我
点击右上角即可分享
微信分享提示