[UOJ UNR#1]奇怪的线段树
来自FallDream的博客,未经允许,请勿转载, 谢谢。
原题可以到UOJ看,传送门
如果存在一个点是白的,却有儿子是黑的,显然无解。
不然的话,只要所有黑色的“黑叶子”节点,即没有黑色的儿子的节点有访问到就行了。
联想到今年CTSC上一道题叫“被操纵的线段树”,每个点被访问之后,可以和他合并的点满足左端点是它的右端点+1,并且和它没有相同的父亲。
发现这些点构成一条链,所以只需要向最大的那个点连边就行了,然后每个点向左儿子连边。
拆点之后,给所有的“黑色叶子”节点中间的边加上流量下界,求出最小流就是答案了。
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<vector> #define S 0 #define T 16001 #define SS 16002 #define TT 16003 #define MN 16003 #define INF 2000000000 using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,q[MN+5],c[MN+5],d[MN+5],head[MN+5],cnt=1,Lt[MN+5],Rt[MN+5],dn=0,m; int in[MN+5],L[MN+5],R[MN+5],s[MN+5],ss[MN+5],fa[MN+5],top; struct edge{int to,next,w;}e[MN*100+5]; vector<int> v[MN+5]; inline void ins(int f,int t,int w) { e[++cnt]=(edge){t,head[f],w};head[f]=cnt; e[++cnt]=(edge){f,head[t],0};head[t]=cnt; } int Build(int l,int r) { int x=++dn;s[x]=read();Lt[x]=l;Rt[x]=r;v[l].push_back(x); if(l!=r) { int mid=read(); fa[L[x]=Build(l,mid)]=x; fa[R[x]=Build(mid+1,r)]=x; ss[x]|=ss[L[x]]|ss[R[x]]; if(!s[x]&&ss[x]){puts("OwO");exit(0);} ins(x,L[x],INF); } if(ss[x]|s[x]) ins(x,x+m,INF); if(s[x]&&!ss[x]) ins(S,x,INF),--in[x],++in[x+m],ins(x+m,T,INF); ss[x]|=s[x];return x; } bool bfs() { memset(d,0,sizeof(d));int i,j; for(d[q[top=i=1]=SS]=1;i<=top;++i) for(j=c[q[i]]=head[q[i]];j;j=e[j].next) if(e[j].w&&!d[e[j].to]) d[q[++top]=e[j].to]=d[q[i]]+1; return d[TT]; } int dfs(int x,int f) { if(x==TT) return f;int used=0; for(int&i=c[x];i;i=e[i].next) if(e[i].w&&d[e[i].to]==d[x]+1) { int w=dfs(e[i].to,min(f-used,e[i].w)); used+=w;e[i].w-=w;e[i^1].w+=w; if(used==f) return f; } return d[x]=-1,used; } int main() { n=read();m=2*n-1;Build(1,n); for(int i=1,j,k;i<=dn;++i) for(j=0,k=Rt[i]+1;j<v[k].size();++j) if(v[k][j]!=R[fa[i]]) {ins(i+m,v[k][j],INF);break;} for(int i=1;i<=dn<<1;++i) if(in[i]>0) ins(SS,i,in[i]); else if(in[i]<0) ins(i,TT,-in[i]); while(bfs()) dfs(SS,INF);ins(T,S,INF); while(bfs()) dfs(SS,INF); printf("%d\n",e[cnt].w); return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream