题目大意
给定一个二分图,两边各有n个点。左边第
你需要找一个满足所有匹配边不相交的最大匹配。
1≤n≤3×105
题目分析
考虑依次加入左边的点,令fi表示在所有匹配数为i的合法方案中,最后一个右边的点的编号最小值。显然(如果不考虑没有方案的
对于所有fi∈[l,r)转移是用fi+1来更新fi+1,对于最大的满足fi<l的i,转移是
代码实现
#include <iostream>
#include <cstdio>
#include <cctype>
#include <stack>
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='0'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N=300050;
int n;
struct SPLAY
{
int son[N][2],size[N],fa[N],f[N],tag[N],mi[N];
stack<int> st;
int tot,root;
bool side(int x){return son[fa[x]][1]==x;}
void update(int x){size[x]=size[son[x][0]]+size[son[x][1]]+1,mi[x]=min(f[x],min(mi[son[x][0]],mi[son[x][1]]));}
void rotate(int x)
{
int y=fa[x];bool s=side(x);
if (fa[y]) son[fa[y]][side(y)]=x;
if (son[x][s^1]) fa[son[x][s^1]]=y;
son[y][s]=son[x][s^1],son[x][s^1]=y;
fa[x]=fa[y],fa[y]=x;
update(y),update(x);
}
void ADD(int x,int y){f[x]+=y,mi[x]+=y,tag[x]+=y;}
void clear(int x)
{
if (tag[x])
{
if (son[x][0]) ADD(son[x][0],tag[x]);
if (son[x][1]) ADD(son[x][1],tag[x]);
tag[x]=0;
}
}
void pushdown(int x,int y)
{
for (;x!=y;st.push(x),x=fa[x]);
for (;!st.empty();clear(st.top()),st.pop());
}
void splay(int x,int y)
{
for (pushdown(x,y);fa[x]!=y;rotate(x))
if (fa[fa[x]]!=y)
if (side(x)==side(fa[x])) rotate(fa[x]);
else rotate(x);
}
int search(int x,int y)
{
clear(x);
if (mi[son[x][1]]<=y) return search(son[x][1],y);
return f[x]<=y?x:search(son[x][0],y);
}
int leftward(int x){return clear(x),son[x][0]?leftward(son[x][0]):x;}
int kth(int x,int y)
{
clear(x);
if (size[son[x][0]]+1==y) return x;
return size[son[x][0]]>=y?kth(son[x][0],y):kth(son[x][1],y-size[son[x][0]]-1);
}
void merge(int x,int y,int &rt)
{
if (!x) rt=y;
else if (!y) rt=x;
else splay(rt=kth(x,size[x]),0),update(fa[son[rt][1]=y]=rt);
}
/*
void split(int x,int y,int &l,int &r)
{
if (!y) l=0,r=x;
else splay(l=kth(x,size[x]),0),fa[r=son[l][1]]=0,son[l][1]=0,update(l);
}
*/
void modify(int l,int r)
{
int x,y,z;
splay(y=search(root,r-1),0),root=y,splay(x=search(root,l-1),0),root=x;
if (x!=y)
{
splay(y,x);
if (z=son[y][1]) fa[z]=son[y][1]=0,update(y);
fa[y]=son[x][1]=0,f[++tot]=l,update(son[fa[tot]=x][1]=tot),update(x);
ADD(y,1),merge(y,z,z),merge(x,z,root);
}
else
{
if (z=son[x][1]) fa[z]=son[x][1]=0,update(x);
f[++tot]=l,update(son[fa[tot]=x][1]=tot),update(x);
merge(x,z,root);
}
y=x==y?tot:y,splay(y,0),root=y;
if (son[y][1])
{
splay(x=leftward(son[y][1]),0),y=son[x][0],z=son[x][1];
fa[y]=son[x][0]=0,fa[z]=son[x][1]=0,merge(y,z,root);
}
}
void init(){mi[0]=n+1,f[root=tot=1]=0,size[tot]=1;}
}t;
int main()
{
freopen("bipartite.in","r",stdin),freopen("bipartite.out","w",stdout);
n=read(),t.init();
for (int i=1,l,r;i<=n;++i) l=read(),r=read(),t.modify(l,r);
printf("%d\n",t.size[t.root]-1);
fclose(stdin),fclose(stdout);
return 0;
}