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; }