[POI2007]EGZ-Driving Exam
能到达所有路的充要条件是能到达左右两端的路
用vector反向建边对每条路左右分别求个最长不上升子序列
预处理出每条路向左向右分别需要多建多少路才能到达最左端和最右端
然后跑个\(\Theta(n)\)的尺取法就可以了
本题最长不上升子序列用vector+zkw线段树比二分更加好想?
原来标程的solve
函数尺取时出锅(但是居然AC了
感谢我自己回来看题解发现看不懂
现在这题解是真题解了
#include"cstdio"
#include"cstring"
#include"iostream"
#include"algorithm"
#include"vector"
using namespace std;
const int MAXN=1<<17;
int n,m,P,K,np;
int f[2][MAXN];
int tree[MAXN<<1];
struct rpg{bool kd;int h,fl,fr;};
vector<rpg> vec[MAXN];
int read()
{
int x=0;char ch=getchar();
while(ch<'0'||'9'<ch) ch=getchar();
while('0'<=ch&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
return x;
}
void calcl()
{
for(int i=1;i<n;++i){
for(int j=0;j<vec[i].size();++j){
if(!vec[i][j].kd){
int l=MAXN+vec[i][j].h-1,r=MAXN+m+2,maxn=0;
while(l^r^1){
if(~l&1) maxn=max(maxn,tree[l^1]);
if(r&1) maxn=max(maxn,tree[r^1]);
l>>=1;r>>=1;
}vec[i][j].fl=maxn+1;
}
}for(int j=0;j<vec[i].size();++j){
if(!vec[i][j].kd){
for(int k=MAXN+vec[i][j].h;k;k>>=1){
tree[k]=max(tree[k],vec[i][j].fl);
}
}
}int l=MAXN,r=MAXN+m+2,maxn=0;
while(l^r^1){
if(~l&1) maxn=max(maxn,tree[l^1]);
if(r&1) maxn=max(maxn,tree[r&1]);
l>>=1,r>>=1;
}f[0][i+1]=maxn;
}return;
}
void calcr()
{
for(int i=n;i>1;--i){
for(int j=0;j<vec[i].size();++j){
if(vec[i][j].kd){
int l=MAXN+vec[i][j].h-1,r=MAXN+m+2,maxn=0;
while(l^r^1){
if(~l&1) maxn=max(maxn,tree[l^1]);
if(r&1) maxn=max(maxn,tree[r^1]);
l>>=1;r>>=1;
}vec[i][j].fr=maxn+1;
}
}for(int j=0;j<vec[i].size();++j){
if(vec[i][j].kd){
for(int k=MAXN+vec[i][j].h;k;k>>=1){
tree[k]=max(tree[k],vec[i][j].fr);
}
}
}int l=MAXN,r=MAXN+m+2,maxn=0;
while(l^r^1){
if(~l&1) maxn=max(maxn,tree[l^1]);
if(r&1) maxn=max(maxn,tree[r&1]);
l>>=1,r>>=1;
}f[1][i-1]=maxn;
}return;
}
void init()
{
n=read(),m=read(),P=read(),K=read();
for(int i=1;i<=P;++i){
int x=read(),y=read(),z=read();
if(z) vec[x].push_back((rpg){z^1,y+1});
else vec[x+1].push_back((rpg){z^1,y+1});
}calcl();memset(tree,0,sizeof(tree));calcr();
for(int i=1;i<=n;++i) f[0][i]=i-f[0][i]-1,f[1][i]=n-i-f[1][i];
return;
}
void solve()
{
int ans=0,ct=0,cnt=0;
for(int i=1;i<=n;++i){
while(ct+1<=n&&f[1][i]+f[0][ct+1]<=K){
++ct;
if(!f[0][ct]&&!f[1][ct]) ++cnt;
}ans=max(ans,ct-i+1-cnt);
if(!f[0][i]&&!f[1][i]) --cnt;
}printf("%d\n",ans);
return;
}
int main()
{
init();
solve();
return 0;
}
用先进的科学技术与思想文化武装起来的人民,是一个国家最巨大的生产力,是一个社会最强大的推动力,是一个民族最坚实的自信力,是一支军队最可靠的战斗力。
——A·H