UOJ #217. 【UNR #1】奇怪的线段树

Description

给出一棵二叉树的结构,每次询问一个区间,将路径上的点染黑,求最小询问次数。

Solution

网络流。

好厉害的题啊 =w=。

首先可以发现的是,询问一个区间,一定是一段连续的左节点加上一段连续的右节点。

如果是左节点,代表区间([l,r]),那么另一个询问的端点一定是([r+1,x])的左节点,也就是说不能出现左右两个节点,因为这样可以向上合并。

如果是右节点,那么只需要满足另一个端点是(r+1)即可。

这样可以跑最小流,首先拆一下点,如果不是最下面的节点,那么对于它其实没有限制,因为如果满足了它下面的节点,它一定有流量。

如果是下面的节点,那么最小流量就是1

题解里好像建了辅助节点,来优化建图。

我并没有建辅助节点,而是将树上的左节点连接起来,因为满足条件的是一段左端点相同的点,所以直连左节点即可。

建树的同时,记录一下左端点为(x)的最靠上的点。

对于右节点就直接连最上面的点即可,左节点就连最上面的点的左节点即可。

Code

#include <bits/stdc++.h>
using namespace std;

#define cg (2*n-1)
#define lc(o) ch[o][0]
#define rc(o) ch[o][1]

const int N = 4080*4;
const int oo = 0x3f3f3f3f;

inline int in(int x=0,char ch=getchar()) { while(ch>'9' || ch<'0') ch=getchar();
	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x; }

int n,rt,flag;
int ch[N][2],b[N],f[N],bb[N],L[N],R[N],tp[N];

struct Edge { int fr,to,fl; };
struct Network {
	vector<Edge> edge;
	vector<int> g[N];
	int S,T,s,t,cnt,k,d[N],cur[N],du[N],p[N];
	
	void AddEdge(int fr,int to,int fl) {
		edge.push_back((Edge) { fr,to,fl });
		edge.push_back((Edge) { to,fr, 0 });
		g[fr].push_back(edge.size()-2);
		g[to].push_back(edge.size()-1);
	}
	void AddEdge(int fr,int to,int l,int r) {
		AddEdge(fr,to,r-l),du[fr]-=l,du[to]+=l;
	}
	int BFS(int s,int t) {
		memset(d,0xff,sizeof(d));
		queue<int> q;
		d[s]=1,q.push(s);
		for(int x;!q.empty();) {
			x=q.front(),q.pop();
			for(int i=0;i<(int)g[x].size();i++) {
				Edge &e=edge[g[x][i]];
				if(e.fl && d[e.to]==-1) d[e.to]=d[x]+1,q.push(e.to);
			}
		}return d[t]!=-1;
	}
	int Dinic(int s,int t) {
		int flow=0;
		for(int x;BFS(s,t);) {
//			puts("qqqwq");
			for(memset(cur,0,sizeof(cur)),x=s,k=0;;) {
				if(x==t) {
					int mine=0,minf=oo;
					for(int i=0;i<k;i++)
						if(edge[p[i]].fl<minf) minf=edge[p[i]].fl,mine=i;
					for(int i=0;i<k;i++) 
						edge[p[i]].fl-=minf,edge[p[i]^1].fl+=minf;
					flow+=minf,k=mine,x=edge[p[mine]].fr;
				}
				for(int &i=cur[x];i<(int)g[x].size();i++) {
					Edge &e=edge[g[x][i]];
					if(d[x]+1==d[e.to] && e.fl) break;
				}
				if(cur[x]<(int)g[x].size()) {
					p[k++]=g[x][cur[x]],
					x=edge[g[x][cur[x]]].to;
				} else {
					if(!k) break;
					d[x]=-1,x=edge[p[--k]].fr;
				}
			}
//			cout<<flow<<endl;
		}return flow;
	}
	void Build(int &x,int l,int r) {
		x=++cnt;
		if(!tp[l]) tp[l]=x;
		L[x]=l,R[x]=r;
		if(l==r) {
			bb[x]=b[x]=in();
			if(b[x]) AddEdge(x,x+cg,1,oo);
		} else {
			b[x]=in();
			int m=in();
			Build(lc(x),l,m),Build(rc(x),m+1,r);
			AddEdge(x+cg,lc(x),0,oo);
			if(bb[lc(x)]||bb[rc(x)]) {
				if(!b[x]) flag=1;
				else AddEdge(x,x+cg,0,oo);
			} else {
				if(b[x]) AddEdge(x,x+cg,1,oo);
			}
			bb[x]=b[x]||bb[lc(x)]||bb[rc(x)];
			f[lc(x)]=f[rc(x)]=x;
		}
	}
	void main() {
		flag=0;
		n=in();
		S=++cnt,T=++cnt,s=++cnt,t=++cnt;
		Build(rt,1,n);
//		puts("qwq");
		if(flag) { cout<<"OwO"<<endl;return; }
		for(int i=1;i<=cg;i++) {
			AddEdge(s,cnt-cg+i,0,oo);
			AddEdge(cnt+i,t,0,oo);
		}
		for(int i=cnt-cg+2;i<=cnt;i++) {
			int d=rc(f[i])==i;
//			cout<<d<<endl;
			if(!d) {
				if(tp[R[i]+1] && lc(tp[R[i]+1])) 
					AddEdge(i+cg,lc(tp[R[i]+1]),0,oo);
			} else {
				if(tp[R[i]+1]) 
					AddEdge(i+cg,tp[R[i]+1],0,oo);
			}
		}
		cnt+=cg;
		for(int i=3;i<=cnt;i++) {
			if(du[i]<0) AddEdge(i,T,-du[i]);
			else if(du[i]>0) AddEdge(S,i,du[i]);
		}
//		for(int i=1;i<=cnt;i++) cout<<du[i]<<" ";cout<<endl;
//		for(int i=0;i<(int)edge.size();i+=2) {
//			cout<<edge[i].fr<<"-->"<<edge[i].to<<" "<<edge[i].fl<<endl;
//		}
		
		Dinic(S,T);
		AddEdge(t,s,oo);
		cout<<Dinic(S,T)<<endl;
	}
}py;

int main() {
	py.main();
	return 0;
}

  

原文地址:https://www.cnblogs.com/beiyuoi/p/6598623.html