题目:http://codeforces.com/contest/809/problem/D
看题解,抄标程...发现自己连 splay 都快不会写了...
首先,题目就是要得到一个 LIS;
但与一般不同的是,新加入的不是一个值,而是一个取值范围;
仍是设 f[i] 表示长度为 i 的 LIS 的结尾最靠前是哪个位置,而此时新出现一个区间 l~r;
如果 f[i] < l,那么可以接上一个 l 变成 f[i+1],也就是 f[i+1] = l;
如果 l <= f[i] <= r,也可以把这个 f[i] 通过选这个区间里的值而尽量提前,最多能提前到上一个 f[j] , l <= f[j] < f[i] <= r;
也就是此时,f[i] = f[j] + 1;
可以知道上一个位置 j 就是 i-1,也就是新增区间带来了这样的转移:f[i] = min( f[i] , f[i-1] + 1),而 f[i-1] + 1 <= f[i] , 所以 f[i] = f[i-1] + 1;
综上,新增加一个区间:
1.会使 l 左边第一个 f[i] < l 转移到 f[i+1] = l;
2.使区间内部的值都向前跳到上一个的后一个,即 f[i+1] = f[i] + 1 , l <= f[i] < f[i+1] <= r;
3.使右边第一个 f[i] > r 转移到 f[i-1] + 1;
可以发现,转移2可以看做是区间内的 f[] 都向右移动了一下,然后区间左边第一个移动到了左端点,右边第一个移到区间内,同时角标(答案)+1;
就可以用 splay 维护,每次找到值在 l~r 范围内的,+1,再删除……,加入……什么的...
然后就模仿了标程的写法...
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ls c[x][0] #define rs c[x][1] using namespace std; int const xn=3e5+5; int n,Q,v[xn],lzy[xn],fa[xn],c[xn][2],rt,ans; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return f?ret:-ret; } void pushdown(int x) { if(!lzy[x])return; v[ls]+=lzy[x]; lzy[ls]+=lzy[x]; v[rs]+=lzy[x]; lzy[rs]+=lzy[x]; lzy[x]=0; } void push(int x) { if(fa[x])push(fa[x]); pushdown(x); } void rotate(int x) { int y=fa[x],z=fa[y],d=(c[y][1]==x); if(z)c[z][c[z][1]==y]=x; fa[x]=z; fa[y]=x; fa[c[x][!d]]=y; c[y][d]=c[x][!d]; c[x][!d]=y; } void splay(int x,int f) { push(x);//! while(fa[x]!=f) { int y=fa[x],z=fa[y]; if(z!=f) { if((c[y][0]==x)^(c[z][0]==y))rotate(x); else rotate(y); } rotate(x); } if(!f)rt=x; } int low(int k)//<=k { int nw=rt,ret=0; while(nw) { pushdown(nw);//!!! if(v[nw]<k)ret=nw,nw=c[nw][1]; else nw=c[nw][0]; } return ret; } int nxt(int x) { splay(x,0); int nw=c[x][1]; while(c[nw][0])nw=c[nw][0]; return nw; } void insert(int &x,int k,int f) { if(!x){v[x=++n]=k; fa[x]=f; splay(x,0); return;} pushdown(x);//!! insert(c[x][k>v[x]],k,x); } void del(int x) { splay(x,0); int p=c[x][0],q=c[x][1]; while(c[p][1])p=c[p][1]; while(c[q][0])q=c[q][0]; splay(p,0); splay(q,p); c[q][0]=0; fa[x]=0; } void solve(int l,int r) { int p=low(l),q=low(r),t=nxt(q); if(p!=q)//! { splay(p,0); splay(t,p); v[c[t][0]]++; lzy[c[t][0]]++; } if(t!=1)del(t),ans--; insert(p,l,0); ans++; } int main() { Q=rd(); v[++n]=(1<<30); v[++n]=-(1<<30); fa[2]=1; c[1][0]=2; rt=1;// for(int i=1,l,r;i<=Q;i++)l=rd(),r=rd(),solve(l,r); printf("%d ",ans); return 0; }