BZOJ # 3218. a + b Problema —— Corte mínimo de flujo de red + construcción de árboles

tema

Explosión oscura P3218

respuesta

Cuando vea el título que dice usar la transmisión en red para hacer A + B, su primera reacción: este es un blog falso

Pero esta pregunta no es A + B, ¡es a + b! (Distingue entre mayúsculas y minúsculas) , encontrará que algo está mal cuando mire el título ...

Para entrar en el tema, primero podemos transformar el problema:

Primero Pireste todo , si el punto es blanco, o si el punto y los puntos calificados anteriores son todos negros, sume Pi.

En este momento, si encuentra un punto S que representa el blanco y T que representa el negro, tome cada punto de la matriz en el gráfico y defina el punto conectado a S con un borde como un punto blanco, y el punto conectado a T con un borde es negro,

Este problema se puede convertir en un problema de corte mínimo.

La capacidad del borde conectado desde S es, y la capacidad del borde w_i + p_iconectado a T es bi(observe la dirección),

Entonces, ¿cómo lidiar con esta condición que requiere que un montón de puntos sean negros?

Puede crear un punto virtual (en consecuencia, el punto en la matriz corresponde al punto en el gráfico es un punto real), y hay Piun borde con una capacidad de conectado a T, porque de acuerdo con los requisitos, si el borde no es corte, el punto virtual se conecta suavemente a T, luego los puntos reales correspondientes que deben ser puntos negros también deben tener bordes conectados a T, por lo que se puede establecer un punto virtual conectado por borde con capacidad INF desde cada punto. Debido a que la capacidad es un valor máximo, este tipo de borde no se puede incluir en el corte mínimo y no se puede cortar.

En este punto, ejecutamos un Dinic de flujo máximo para encontrar el corte mínimo, y luego lo restamos de la suma de las capacidades de los bordes (excepto el borde INF) ¿Pronto se resolvió?

Sin embargo, el alcance de esta pregunta es muy poco amigable n \ leq 5000Según el método de mapeo anterior, aunque el número de puntos es el Sobre)nivel, el número de lados O (n ^ 2);

El espacio tampoco es amigable, cada punto de prueba tiene solo 48 MB, por lo que tuve que abrir int con cuidado. .

Por lo tanto, consideramos reducir el número de aristas creando más puntos virtuales Hay muchos métodos específicos y hay más de una partición óptica.

Solo presentaré una forma muy segura de crear un árbol de presidente virtual.

Específicamente, después de discretizar todos los valores de a, lyr , a_jse establece un árbol de segmento de línea ponderado para todos los prefijos (1≤j≤i) Bi, y cada intervalo en el árbol de segmento de línea representa uno en la figura. Punto imaginario

Definimos esto como el intervalo de puntos (por conveniencia, lo previamente establecido con una capacidad de Piaristas conectadas al punto T son las condiciones imaginarias de puntos), entonces el árbol Bien el intervalo (l, r) correspondiente a la sección de puntos debe Satisfacer que todo 1 \ leq j \ leq i, l \ leq a_j \ leq rj corresponde al punto real en el gráfico conectado directa o indirectamente al borde INF a través de otros puntos imaginarios en el intervalo.

Esta oración es un poco larga, pero definitivamente se puede entender. Para cumplir esta condición, solo es necesario conectar el punto imaginario correspondiente al intervalo entre el hijo izquierdo y el hijo derecho a él, y el punto real que satisface la condición se conecta al nodo hoja,

Porque  a \ overset {inf} {\ rightarrow} b y  a \ overset {inf} {\ rightarrow} c (Punto virtual) \ overset {inf} {\ rightarrow} b son equivalentes, por lo que cada árbol B_ {i-1}encontrado (encendido l_i, r_i) corresponde a una pluralidad de rango de puntos virtuales, en lugar del punto virtual original correspondiente a la condición para estar conectado a un número de nuestros puntos negros de puntos sólidos establecidos, correspondientes a un máximo porque hay log_2nun intervalo, en la mayoría de los log_2nbordes nuevos ,

Luego, para cada árbol B, usamos el árbol del presidente para abrir puntos dinámicamente y crear como máximo log_2nun punto y un 2log_2nborde cada vez , de modo que el número total de puntos en el gráfico no exceda nlog_2n \ cdot C, el número total de bordes no exceda nlog_2n \ cdot D(C y D son constantes <10), y el espacio no lo es. Explotará, y resulta que Dinic puede ejecutarlo.

Código

Se agregaron algunas optimizaciones innecesarias, solo entiéndelo

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<climits>
#include<map>
#define ll long long
#define MAXN 400005    //边数点数大概是这个数量级
#define mst0(x) memset(x,0,sizeof(x))
#define INF 0x3f3f3f3f
using namespace std;
inline ll read(){
	ll x=0;bool f=1;char s=getchar();
	while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
	while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+s-'0',s=getchar();
	return f?x:-x;
}
int n,IN,N;
int in[5005][6],SUM;
map<int,int>mp;
int root[MAXN],NN,XP,R;

int f[MAXN];
int d[MAXN],cur[MAXN];
struct edge{
	int v,id;edge(){}
	edge(int V,int I){v=V,id=I;}
};
vector<edge>G[MAXN];
queue<int>q;
bool ct[MAXN];
inline bool bfs(int S,int T){
	for(int i=0,lm=min(XP,MAXN-5);i<=lm;i++)d[i]=-1;
	q.push(S),d[S]=0;
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=0;i<G[u].size();i++){
			int v=G[u][i].v,a=G[u][i].id;
			if(ct[v]&&f[a]>0&&d[v]<0)d[v]=d[u]+1,q.push(v);
		}
	}
	return d[T]>=0;
}
inline int dfs(int x,int lim,int T){
	if(x==T)return lim;
	int res=lim;
	for(int i=cur[x];i<G[x].size()&&res>0;i++){
		cur[x]=i;    //当前弧优化
		int v=G[x][i].v,a=G[x][i].id;
		if(ct[v]&&f[a]>0&&d[v]==d[x]+1){
			int ad=dfs(v,min(res,f[a]),T);
			f[a]-=ad,f[a^1]+=ad,res-=ad;
		}
	}
	if(lim==res)d[x]=-1;    //吔屎优化
	return lim-res;
}
inline int dinic(int S,int T){
	int res=0;
	while(bfs(S,T)){
		for(int i=0,lm=min(XP,MAXN-5);i<=lm;i++)cur[i]=0;
		while(int ad=dfs(S,INF,T))res+=ad;
	}
	return res;
}
inline void addedge(int u,int v,int w){
	if(w<INF)SUM+=w;
	f[IN]=w,f[IN^1]=0;
	G[u].push_back(edge(v,IN));
	G[v].push_back(edge(u,IN^1));
	IN+=2;
}

struct itn{
	int ls,rs,id;
}t[MAXN];
inline void add(int x,int y,int l,int r,int u){
	if(y>0)addedge(t[y].id,t[x].id,INF);    //把先前点y的信息通过连边转过来
	if(l==r){addedge(u,t[x].id,INF);return;}
	int mid=(l+r)>>1;
	if(in[u][0]<=mid){
		t[x].rs=t[y].rs,t[x].ls=++NN,t[t[x].ls].id=++XP;//另一儿子无需连边,因为先前点y的信息已经转过来了
		add(t[x].ls,t[y].ls,l,mid,u);
		addedge(t[t[x].ls].id,t[x].id,INF);
	}
	else{
		t[x].ls=t[y].ls,t[x].rs=++NN,t[t[x].rs].id=++XP;
		add(t[x].rs,t[y].rs,mid+1,r,u);
		addedge(t[t[x].rs].id,t[x].id,INF);
	}
}
inline void sch(int x,int l,int r,int a,int b,int p){
	if(x==0)return;
	if(l==a&&r==b){addedge(t[x].id,p,INF);return;}
	int mid=(l+r)>>1;
	if(a<=mid)sch(t[x].ls,l,mid,a,min(mid,b),p);
	if(b>mid)sch(t[x].rs,mid+1,r,max(a,mid+1),b,p);
}
inline void DFS(int x){
	if(ct[x])return;ct[x]=1;
	for(int i=0;i<G[x].size();i++)
		if(G[x][i].id&1)DFS(G[x][i].v);
}

int main()
{
	n=read(),N=(n<<1)+1;
	for(int i=1;i<=n;i++){
		for(int j=0;j<6;j++)in[i][j]=read();
		SUM-=in[i][5];
		mp[in[i][0]]=1,mp[in[i][3]]=1,mp[in[i][4]]=1;
	}
	map<int,int>::iterator it;
	for(it=mp.begin();it!=mp.end();it++)it->second=++R;
	for(int i=1;i<=n;i++)
		in[i][0]=mp[in[i][0]],in[i][3]=mp[in[i][3]],in[i][4]=mp[in[i][4]];
	XP=N;
	for(int i=1;i<=n;i++){
		addedge(0,i,in[i][2]+in[i][5]);
		if(i==1)addedge(i,N,in[i][1]+in[i][5]);
		else addedge(i,N,in[i][1]),
		addedge(n+i,N,in[i][5]),addedge(i,n+i,INF);
		sch(root[i-1],1,R,in[i][3],in[i][4],n+i);
		if(i<n){
			root[i]=++NN,t[root[i]].id=++XP;
			add(root[i],root[i-1],1,R,i);
		}
	}
	DFS(N);    //把最终无法通向T的点删去,免跑
	printf("%d\n",SUM-dinic(0,N));
	return 0;
}

 

Supongo que te gusta

Origin blog.csdn.net/weixin_43960287/article/details/113704427
Recomendado
Clasificación