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即可。
以下代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }