Description
小C有一个特殊的二分图(有着X部与Y部)。
对于一个X部的点x,对应在Y部的相邻点只会是一个连续区间。
然后你需要找一个最大匹配,这个匹配经过小C的膜法也变得特殊了。
两个匹配边只有当不相交时候才是小C的匹配(即对于一个比配xi->yi,xj->yj,如果xi
Solution
先来想一个比较靠谱的暴力,
对于Y部开一个数组,
对于每个X部的点,把它的Y部的
l r
从后往前遍历,对于每一个位置i,更新为:
fi=max(fi,max{f1...fi−1}+1)
最后直接输出f的最大值即可
复杂度: O(∑(ri−li+1))
想一下怎么优化,
首先发现如果把f变成不下降的,答案也不会变;
那么,每次的改变只是把一段相同的f的开头向前移动几位,
做每个X部的点时,如果一段相同f的开头在区间内,那么这个开头一定会移动到它前面一段的开头后面一位(当然不能移动到区间之外),(读者可以自己画图试试看)
那么,试着只记录每段相同的开头,那么每次操作只要把区间内的数更改即可,
我们发现,每次找到对应的区间后,把这个区间的最后一个数删掉,把剩下的数全部+1,再在区间前插入
l
这个数,这样就相当于把区间的每个数都改成它前面的数的+1(当然不能移动到区间之外);
这个用Splay维护一下,
复杂度:
Code
#include <cstdio>
#include <cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define min(q,w) ((q)<(w)?(q):(w))
#define max(q,w) ((q)>(w)?(q):(w))
using namespace std;
const int N=300500;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans,mx;
int a[N][2],b0;
struct qqww
{
int v,mi,la,mx,l,r,fa,si;
}b[N];
int root;
void merge(int q)
{
b[q].si=b[b[q].l].si+1+b[b[q].r].si;
b[q].mi=min(b[q].v,min(b[b[q].l].mi,b[b[q].r].mi));
b[q].mx=max(b[q].v,max(b[b[q].l].mx,b[b[q].r].mx));
}
void doit(int q)
{
if(!b[q].la)return;
b[q].mi+=b[q].la,b[q].mx+=b[q].la;
b[q].v+=b[q].la;
if(b[q].l)b[b[q].l].la+=b[q].la;
if(b[q].r)b[b[q].r].la+=b[q].la;
b[q].la=0;
}
int search1(int q,int e)
{
doit(b[q].l),doit(b[q].r);
if(b[b[q].l].mx>e&&b[q].l)return search1(b[q].l,e);
if(b[q].v>e||!b[q].r)return q;
return search1(b[q].r,e);
}
int search2(int q,int e)
{
doit(b[q].l),doit(b[q].r);
if(b[b[q].r].mi<e&&b[q].r)return search2(b[q].r,e);
if(b[q].v<e||!b[q].l)return q;
return search2(b[q].l,e);
}
bool SD(int q){return b[b[q].fa].r==q;}
void rotate(int q)
{
int t=b[q].fa;
if(SD(t))b[b[t].fa].r=q;
else b[b[t].fa].l=q;
if(SD(q))b[t].r=b[q].l,b[b[q].l].fa=t,b[q].l=t;
else b[t].l=b[q].r,b[b[q].r].fa=t,b[q].r=t;
b[q].fa=b[t].fa;b[t].fa=q;
merge(t),merge(q);
}
void Splay(int q,int T)
{
while(b[q].fa!=T)
{
if(b[b[q].fa].fa!=T)
if(SD(q)==SD(b[q].fa))rotate(b[q].fa);
else rotate(q);
rotate(q);
}
if(!T)root=q;
}
void delt(int q)
{
q=search2(root,q);
if(q==2)return;
Splay(q,0);
Splay(q=search2(b[q].r,-1),root);
if(q==2)return;
b[root].r=b[q].r;
b[b[q].r].fa=root;
merge(root);
}
void change_jia(int q,int w)
{
Splay(q=search2(root,q),0);
w=search1(root,w);
if(q==w)return;
Splay(w,root);
q=b[w].l;if(!q)return;
b[q].la++;
doit(q);
merge(b[q].fa),merge(root);
}
void change_join(int q1)
{
int q;
Splay(q=search2(root,q1),0);
b0++;
b[b0].fa=q;b[b0].v=q1;
b[b0].r=b[q].r;b[b[q].r].fa=b0;
b[q].r=b0;
merge(b0),merge(root);
}
int main()
{
read(n);
fo(i,1,n)read(a[i][0]),read(a[i][1]);
root=1;b[0].mi=b[0].v=1e9;
b[1].r=2;
b[2].fa=1,b[2].v=1e9;
merge(2),merge(1);b0=2;
fo(i,1,n)
{
delt(a[i][1]);
change_jia(a[i][0],a[i][1]);
change_join(a[i][0]);
}
printf("%d\n",b[root].si-2);
return 0;
}