树套树入门题
luogu4093 序列
这个题首先考虑的算法肯定是dp了(如果数据不毒瘤的话)
f[0]=0;ans=0;
for (rint i=1;i<=n;i++)
for (rint j=0;j<=i-1;j++)
if (minn[i]>=a[j] && maxx[j]<=a[i])
f[i]=max(f[i],f[j]+1);
for (rint i=1;i<=n;i++) ans=max(ans,f[i]);
cout<<ans;
当然这个题既然让你树套树,你就肯定得树套树……显然这个O(n2)的DP会爆掉…… 因为我们树套树只学过怎么二维数点,而前面又有正好两个表达式——对于点i,可以转移过来的点j必须满足三个式子
1<=j<=i
a[j]<=minn[i]
maxx[j]<=a[i]
所以我现在有一个思路:用扫描线去掉第一维,剩下的线段树套线段树,外层的下标是a[j],内层的的下标是maxx[j],维护的是f[i]的最大值,这样我们就可以现在外层查询(1,minn[i])以内的点,内层查(1,a[i])以内,查到的就是满足这两个条件的最大的f[j],记为ans。 我们可以再写一个这样的dp方程,f[i]=ans+1;
那么我们再看复杂度,树套树是(log2n),扫描线是(n),相乘就是(nlog2n),考虑时限两秒,完全可以应付。 等等,这TM是正解?我竟然推出来了?
#include<iostream>
#include<cstdio>
#include<cstring>
#define rint register int
#define inv inline void
#define ini inline int
#define big 1e9
#define maxn 100010
#define mid (l+r>>1)
using namespace std;
int f[maxn],a[maxn],minn[maxn],maxx[maxn];
int n,m,cnt,rt;
ini read()
{
char c;int r=0,f=1;
while (c<'0' || c>'9')
{
if (c=='-') f=-1;
c=getchar();
}
while (c>='0' && c<='9')
{
r=r*10+c-'0';
c=getchar();
}
return r*f;
}
struct IN_node
{
int val,ls,rs;
}in[maxn<<7];
struct OUT_node
{
int pos,ls,rs;
}out[maxn<<2];
inv build(int l,int r,int &num)
{
if (!num) num=++cnt;
if (l==r) return;
build(l,mid,out[num].ls);
build(mid+1,r,out[num].rs);
}
inv changeY(int l,int r,int &num,int x,int c)
{
if (!num) num=++cnt;
in[num].val=max(in[num].val,c);
if (l==r) return;
if (x<=mid) changeY(l,mid,in[num].ls,x,c);
else changeY(mid+1,r,in[num].rs,x,c);
}
inv changeX(int l,int r,int num,int x,int y,int c)
{
changeY(1,maxn,out[num].pos,y,c);
if (l==r) return;
if (x<=mid) changeX(l,mid,out[num].ls,x,y,c);
else changeX(mid+1,r,out[num].rs,x,y,c);
}
ini queryY(int L,int R,int l,int r,int num)
{
if (!num) return 0;
if (L<=l && r<=R) return in[num].val;
int res=0;
if (L<=mid) res=max(res,queryY(L,R,l,mid,in[num].ls));
if (R>mid) res=max(res,queryY(L,R,mid+1,r,in[num].rs));
return res;
}
ini queryX(int l,int r,int num,int L1,int R1,int L2,int R2)
{
if (L1<=l && r<=R1) return queryY(L2,R2,1,maxn,out[num].pos);
// zz错误↑↑ zz错误之二↑↑
int res=0;
if (L1<=mid) res=max(res,queryX(l,mid,out[num].ls,L1,R1,L2,R2));
if (R1>mid) res=max(res,queryX(mid+1,r,out[num].rs,L1,R1,L2,R2));
return res;
}
int main()
{
n=read();m=read();
for (rint i=1;i<=n;i++)
{
a[i]=read();
minn[i]=maxx[i]=a[i];
}
for (rint i=1;i<=m;i++)
{
int x,y;x=read();y=read();
if (minn[x]>y) minn[x]=y;
if (maxx[x]<y) maxx[x]=y;
}
build(1,maxn,rt);
int ans=0;
for (rint i=1;i<=n;i++)
{
f[i]=queryX(1,maxn,rt,1,minn[i],1,a[i])+1;
changeX(1,maxn,rt,a[i],maxx[i],f[i]);
ans=max(ans,f[i]);
}
printf("%d",ans);
}
赞 赏
蒟蒻的邮箱:xmzl200201@126.com