uoj#217. 【UNR #1】奇怪的線段樹(上下界最小流)
阿新 • • 發佈:2020-08-02
題目描述
n<=4000
題解
線段樹性質:一次區間查詢從左往右對應右子樹->右子樹->...->左子樹->左子樹
把[l,r]向r+1連邊,r+1向[r+1,l']連邊,跑上下界最小流即可
上下界最小流=上下界可行流-殘量網路T->S最大流,可行流=T->S的inf邊跑過的流量
染色樹的葉子節點要經過至少一次,非葉子可以經過任意次,沒有染色的點不能經過
code
#include <bits/stdc++.h> #define fo(a,b,c) for (a=b; a<=c; a++) #define fd(a,b,c) for (a=b; a>=c; a--) #define min(a,b) (a<b?a:b) #define max(a,b) (a>b?a:b) #define inf 114514 #define ll long long //#define file using namespace std; int a[2000001][3],tr[8001][2],d[8001],ls[30001],cur[30001],f[30001],g[30001]; int L[8001],R[8001],Tr[8001],A[8001],B[8001],n,i,j,k,l,t,tot,t1,t2,len,ans,S,T; bool bz1[8001],bz2[8001]; void NEW(int x,int y,int z) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;a[len][2]=z;} void New(int x,int y,int z) {NEW(x,y,z),NEW(y,x,0);} void pd(int Fa,int t) { if (Tr[t] && (!tr[t][0] || !Tr[tr[t][0]] && !Tr[tr[t][1]])) { if (tr[Fa][0]==t) bz1[t]=1; else bz2[t]=1; } if (t>1) {if (tr[Fa][0]==t) A[++t1]=t; else B[++t2]=t;} if (!tr[t][0]) return; if (!Tr[t] && Tr[tr[t][0]]) {printf("OwO\n");exit(0);} if (!Tr[t] && Tr[tr[t][1]]) {printf("OwO\n");exit(0);} pd(t,tr[t][0]),pd(t,tr[t][1]); } int dfs(int t,int flow) { int i,use=0,w; if (t==T) return flow; for (i=cur[t]; i; i=a[i][1]) if (a[i][2] && f[t]==f[a[i][0]]+1) { cur[t]=i; w=dfs(a[i][0],min(flow-use,a[i][2])); a[i][2]-=w,a[i^1][2]+=w; use+=w; if (flow==use) return use; } cur[t]=ls[t]; --g[f[t]]; if (!g[f[t]]) {f[S]=T+1;return use;} ++f[t],++g[f[t]]; return use; } int main() { #ifdef file freopen("uoj217.in","r",stdin); #endif scanf("%d",&n); t=tot=1;L[1]=1;R[1]=n;d[t]=1; fo(i,1,n*2-1) { scanf("%d",&j);Tr[d[t]]=j; if (L[d[t]]!=R[d[t]]) { scanf("%d",&k); tr[d[t]][0]=++tot;L[tot]=L[d[t]];R[tot]=k; tr[d[t]][1]=++tot;L[tot]=k+1;R[tot]=R[d[t]]; l=d[t],d[++t]=tr[l][0]; } else { --t; while (t && tr[d[t]][1]==d[t+1]) --t; if (t) l=d[t],d[++t]=tr[l][1]; } } pd(0,1); if (!Tr[1]) {printf("0\n");return 0;} if (Tr[1] && !Tr[tr[1][0]] && !Tr[tr[1][1]]) {printf("1\n");return 0;} S=(n+tot)*2+1;T=S+1; len=1; fo(i,1,n) New(i,i+n,inf); fo(i,1,t2) if (Tr[B[i]]) { New(T,B[i]+n*2,inf); New(B[i]+n*2,B[i]+n*2+tot,inf); if (bz2[B[i]]) New(T+1,B[i]+n*2+tot,1),New(B[i]+n*2,T+2,1); New(B[i]+n*2+tot,S,inf); New(L[B[i]],B[i]+n*2,inf); if (R[B[i]]<n) New(B[i]+n*2+tot,R[B[i]]+1,inf); } fo(i,1,t1) if (Tr[A[i]]) { New(T,A[i]+n*2,inf); New(A[i]+n*2,A[i]+n*2+tot,inf); if (bz1[A[i]]) New(T+1,A[i]+n*2+tot,1),New(A[i]+n*2,T+2,1); New(A[i]+n*2+tot,S,inf); New(L[A[i]]+n,A[i]+n*2,inf); if (R[A[i]]<n) New(A[i]+n*2+tot,R[A[i]]+n+1,inf); } New(S,T,inf); S+=2,T+=2;g[0]=T; while (f[S]<=T) dfs(S,inf);ans=a[len][2]; memset(f,0,sizeof(f)),memset(g,0,sizeof(g)),memset(cur,0,sizeof(cur)); S-=2,T-=2;g[0]=T;a[len][2]=a[len^1][2]=0; while (f[S]<=T) ans-=dfs(S,inf); printf("%d\n",ans); fclose(stdin); fclose(stdout); return 0; }