Problem
Solution
又是大神题。。在做dp的时候不知怎么就做到了这道题,可能跟dp唯一有点关系的可能就是lis了吧?
考虑把边反向,那么就是要1~n所有点都能到达i,那么就只需1,n满足条件即可。
不妨令f[i]表示1可以达i最少需要多少建多少条边,贪心一下,就是利用起左边的lis,然后建其他的边。
求lis可以用树状数组搞。
怎么统计答案?f是单调不降的,g是单调不升的,那么two pointer一下枚举左右端点就好了。cnt统计的是本来就满足条件的边数。
Code
#include <cstring>
#include <cstdio>
#define rg register
#define lowbit(x) ((x)&(-(x)))
using namespace std;
typedef long long ll;
const int maxn=100010;
template <typename Tp> inline void getmin(Tp &x,Tp y){if(y<x) x=y;}
template <typename Tp> inline void getmax(Tp &x,Tp y){if(y>x) x=y;}
template <typename Tp> inline void read(Tp &x)
{
x=0;int f=0;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
if(f) x=-x;
}
struct data{int v,w,nxt;};
struct List{
int p,head[maxn];data edge[maxn];
inline void insert(int u,int v)
{
edge[++p]=(data){v,0,head[u]};head[u]=p;
}
}l,r;
int n,m,p,k,x,y,dir,ans,cnt,f[maxn],g[maxn],t[maxn];
inline void add(int p,int v){for(;p<=m;p+=lowbit(p)) getmax(t[p],v);}
int query(int p,int res=0){for(;p;p-=lowbit(p)) getmax(res,t[p]);return res;}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
read(n);read(m);read(p);read(k);m++;
for(rg int i=1;i<=p;i++)
{
read(x);read(y);read(dir);y=m-y;
if(dir) l.insert(x+1,y);
else r.insert(x,y);
}
for(rg int i=2;i<=n;i++)
{
for(int j=l.head[i];j;j=l.edge[j].nxt)
getmax(f[i],l.edge[j].w=query(l.edge[j].v)+1);
for(int j=l.head[i];j;j=l.edge[j].nxt)
add(l.edge[j].v,l.edge[j].w);
f[i+1]=f[i];f[i]=i-f[i]-1;
}
memset(t,0,sizeof(t));
for(rg int i=n-1;i;i--)
{
for(int j=r.head[i];j;j=r.edge[j].nxt)
getmax(g[i],r.edge[j].w=query(r.edge[j].v)+1);
for(int j=r.head[i];j;j=r.edge[j].nxt)
add(r.edge[j].v,r.edge[j].w);
g[i-1]=g[i];g[i]=n-i-g[i];
}
for(rg int i=1,j=1;i<=n;i++)
{
while(j<=n&&g[i]+f[j]<=k) j++;
getmax(ans,j-i);
if(!f[i]&&!g[i]) cnt++;
}
printf("%d\n",ans-cnt);
return 0;
}