1. 程式人生 > >2019.01.02-dtoj-4100-yjqb

2019.01.02-dtoj-4100-yjqb

題目描述:

給定一個二分圖,兩個部分我們稱之為A部和B部。
對於一個A部的點A,其在B部中相鄰的點是一個連續的區間,記為[Li,Ri]。
現在你需要找一個儘量大的匹配,使之在具有匹配的性質的前提下,所有匹配邊互不相交。(即不存在兩條匹配邊(Ai,Bx),(Aj,By),使得(i<j,x>y))。

演算法標籤:dp,splay

思路:

令f[i][j],i表示A部匹配到第i個,j表示B部匹配到第j個

有以下兩個轉移式:

f[i][j]=f[i-1][j];
對於li≤j≤ri,f[i][j]=f[i-1][j-1]+1;

我們發現兩個式子都只與i-1有關,於是我們可以把第二維消去。觀察發現,每一位與前一位的差值只為0或1。於是考慮差分,並且用splay維護區間關係。

每次把ri後的第一個1刪去,沒有1則刪去最後一個0,在li的位置上加上一個1,表示把整個[Li,Ri]區間右移一格,並且選中區間的第一個比前一個多1。

統計答案看總共有多少個1即可。

以下程式碼:

#include<bits/stdc++.h>
#define il inline
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=1e5+5;
int n,l[N],r[N],rt,sum[N],son[N][2],sz[N],val[N],fa[N];
il 
int read(){int x;char ch;_(!);x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return x;} il void update(int x){ sz[x]=sz[son[x][0]]+sz[son[x][1]]+1; sum[x]=sum[son[x][0]]+sum[son[x][1]]+val[x]; } il void build(int x,int l,int r){ int mid=(l+r)>>1;fa[mid]=x; if(mid<x)son[x][0
]=mid;else son[x][1]=mid; if(l<mid)build(mid,l,mid-1); if(mid<r)build(mid,mid+1,r); sz[mid]=sz[son[mid][0]]+sz[son[mid][1]]+1; } il void rotate(int x,int &k){ int y=fa[x],z=fa[y],tp=(son[y][1]==x); if(y!=k)son[z][son[z][1]==y]=x;else k=x; son[y][tp]=son[x][tp^1];fa[son[y][tp]]=y; son[x][tp^1]=y;fa[y]=x;fa[x]=z; sz[x]=sz[y];sum[x]=sum[y]; update(y); } il void splay(int x,int &k){ while(x!=k){ int y=fa[x],z=fa[y]; if(y!=k)((son[y][0]==x)^(son[z][0]==y))?rotate(x,k):rotate(y,k); rotate(x,k); } } il int kth(int x,int k){ if(sz[son[x][0]]+1==k)return x; if(sz[son[x][0]]>=k)return kth(son[x][0],k); return kth(son[x][1],k-1-sz[son[x][0]]); } il int fp(int x){ if(sum[son[x][0]])return fp(son[x][0]); if(val[x])return x; return fp(son[x][1]); } il void del(int x){ splay(x,rt); int rk=sz[son[x][0]]+1; int a=kth(rt,rk-1),b=kth(rt,rk+1); splay(a,rt);splay(b,son[a][1]); if(val[x])sum[a]--,sum[b]--,val[x]=0; son[b][0]=sz[x]=fa[x]=0;sz[a]--;sz[b]--; } int main() { n=read();for(int i=1;i<=n;i++)l[i]=read(),r[i]=read(); build(0,1,n+2);rt=(n+3)>>1; for(int i=1;i<=n;i++){ int x=kth(rt,r[i]); splay(x,rt); if(sum[son[x][1]])x=fp(son[x][1]); else while(son[x][1])x=son[x][1]; del(x); int a=kth(rt,l[i]),b=kth(rt,l[i]+1); splay(a,rt);splay(b,son[a][1]); son[b][0]=x;val[x]=sum[x]=sz[x]=1; sum[a]++;sum[b]++;sz[a]++;sz[b]++;fa[x]=b; } printf("%d\n",sum[rt]); return 0; }
View Code