zoukankan      html  css  js  c++  java
  • nfls20034 12449

    pb 出的毒瘤场,也就这题比较可做了(还是在 hsc 提示思路下),所以单独写个题解。


    nmd 老子上午和下午全部在调这题(包括线段树合并的做法)。

    首先可以感性地发现这个题不弱于 CF490F 树上全局 LIS。一个证明:我们可以将原树复制一遍,中间用一条边连接,这样无论删除哪个点都会剩下一棵完整的原树,而删除连接的两端之后跑该题应该恰好等于原树的全局 LIS,这样就把全局 LIS 归约到了这题。

    一个直接的思路是换根。使用 CF490F 的线段树合并做法可以在固定根的时候求出每个子树内的 LIS,这样如果换根成功的话,可以把根的所有儿子子树取个 max。但是很可惜,线段树合并复杂度是均摊的,换根会破坏复杂度。(包括下面要说的长剖做法,更不行了,因为长剖是建立在有根的基础上的。。。)

    但是可以发现:任意找到一条 LIS,如果删除 LIS 所在极小链以外的节点,那么不会破坏该 LIS,删除之后的连通块的最大 LIS 显然依然等于原来的 LIS。所以我们只需要任意找一条 LIS 所在链,求出以上面所有节点为根时的答案即可,稍后我们将看到这是容易的。这个思路就很妙啊,跟《God 的高妙算法》那题异曲同工,树上解决不了的问题,就先用一个简单的步骤将候选答案集合筛成一条链,进而转化为序列问题。

    我们选 (1) 为根时,删除一个点后,只有它父亲所在连通块还没被计算出(其它都是子树),想要换根其实就是想要解决这个问题。现在只要求链上所有节点答案的话,不难发现以链的两端为根时,对每个链上的点至少会有一种情形使得它在 (1) 为根时父亲所在连通块为当前的儿子树。那么就先以 (1) 为根跑一遍全局 LIS,然后以两端为根,这样总共跑三遍即可。而且 DP 时还要记录具体的路径端点,这就要套一堆 pair,讨论也烦很多,异常难写。然后 5e5 2s,跑三遍线段树合并还套 pair 就非常卡常好吧,我尽了所有努力最终只能卡到 2.8s,所以不得不换个常数小的做法。

    观察 CF490F 的题解区发现一个长剖 + 二分的小常数做法,现在来搬运一波。之前是设 DP 状态为 (x) 子树内从 (x) 往下的直 LIS / LDS,考虑交换一下定义域和值域:设 (dp_{x,d}) 为子树 (x) 内长度为 (d) 的直 LIS / LDS 的最上面的最大值 / 最小值。由于 (dp_x) 数组长度与子树 (x) 深度成线性,考虑长剖优化。继承深儿子的话,这回是 push_back 而非 push_front,不需要 deque,直接 vector 即可(开 O2 下并不太需要担心 vector 常数,所以也不用写繁琐的指针写法,继承直接用 swap 函数是 (mathrm O(1)) 的)。转移的话,合并的时候直接往上 max 即可。更新答案的话,还是跟线段树合并一样分三类,容易发现 (dp_x)​ 数组一定是单调的,所以可以直接在被合并数组上二分。枚举!!二分!!!多好写啊。然而还是有很多细节。虽然二分的常数乘以 6,但还是不需要刻意卡常就过了。

    「铁」个毒瘤代码:
    #include<bits/stdc++.h>
    using namespace std;
    #define mp make_pair
    #define X first
    #define Y second
    #define pb push_back
    const int inf=0x3f3f3f3f;
    const int N=5e5+10;
    int n;
    vector<int> nei[N];
    int a[N];
    int mxdep[N],dson[N];
    void dfs1(int x,int fa=0){
    	mxdep[x]=1;
    	for(int i=0;i<nei[x].size();i++){
    		int y=nei[x][i];
    		if(y==fa)continue;
    		dfs1(y,x);
    		mxdep[x]=max(mxdep[x],mxdep[y]+1);
    		if(mxdep[y]>mxdep[dson[x]])dson[x]=y;
    		assert(mxdep[y]>0);
    	}
    }
    pair<int,pair<int,int> > ans[N],tot[N];
    vector<pair<int,int> > dp_i[N],dp_d[N];
    int rl[N];
    void dfs2(int x,int fa=0){
    	ans[x]=tot[x]=mp(0,mp(0,0));
    	for(int i=0;i<nei[x].size();i++){
    		int y=nei[x][i];
    		if(y==fa||y==dson[x])continue;
    		dfs2(y,x);
    		tot[x]=max(tot[x],tot[y]),rl[x]=max(rl[x],tot[y].X);
    	}
    	if(dson[x]){
    		dfs2(dson[x],x),dp_i[x].swap(dp_i[dson[x]]),dp_d[x].swap(dp_d[dson[x]]);
    		tot[x]=max(tot[x],tot[dson[x]]),rl[x]=max(rl[x],tot[dson[x]].X);
    	}
    	else dp_i[x].resize(1,mp(inf,x)),dp_d[x].resize(1,mp(0,x));
    	for(int i=0;i<nei[x].size();i++){
    		int y=nei[x][i];
    		if(y==fa||y==dson[x])continue;
    		for(int j=1;j<=mxdep[y];j++){
    //			assert(dp_i[y][j].X<inf);assert(dp_d[y][j].X);
    			vector<pair<int,int> >::iterator fd;
    			if(dp_i[y][j].X>a[x]){
    				fd=lower_bound(dp_d[x].begin()+1,dp_d[x].end(),mp(a[x],0));
    				if(fd!=dp_d[x].begin()+1)ans[x]=max(ans[x],mp(int(fd-dp_d[x].begin()+j),mp(dp_i[y][j].Y,(fd-1)->Y)));
    			}
    			if(dp_d[y][j].X<a[x]){
    				fd=lower_bound(dp_i[x].begin()+1,dp_i[x].end(),mp(a[x],inf),greater<pair<int,int> >());
    				if(fd!=dp_i[x].begin()+1)ans[x]=max(ans[x],mp(int(fd-dp_i[x].begin()+j),mp(dp_d[y][j].Y,(fd-1)->Y)));
    			}
    			if(dp_i[y][j].X){
    				fd=lower_bound(dp_d[x].begin()+1,dp_d[x].end(),mp(dp_i[y][j].X,0));
    //				if(!(fd-1)->Y)cout<<fd-dp_d[x].begin()-1<<"!
    ";
    				if(fd!=dp_d[x].begin()+1)ans[x]=max(ans[x],mp(int(fd-1-dp_d[x].begin()+j),mp(dp_i[y][j].Y,(fd-1)->Y)));
    			}
    			if(dp_d[y][j].X<inf){
    				fd=lower_bound(dp_i[x].begin()+1,dp_i[x].end(),mp(dp_d[y][j].X,inf),greater<pair<int,int> >());
    				if(fd!=dp_i[x].begin()+1)ans[x]=max(ans[x],mp(int(fd-1-dp_i[x].begin()+j),mp(dp_d[y][j].Y,(fd-1)->Y)));
    			}
    		}
    		for(int j=1;j<=mxdep[y];j++)dp_i[x][j]=max(dp_i[x][j],dp_i[y][j]),dp_d[x][j]=min(dp_d[x][j],dp_d[y][j]);
    	}
    	dp_d[x].pb(mp(inf,0)),dp_i[x].pb(mp(0,0));
    	vector<pair<int,int> >::iterator fd;
    	fd=lower_bound(dp_d[x].begin(),dp_d[x].end(),mp(a[x],0));
    	ans[x]=max(ans[x],mp(int(fd-dp_d[x].begin()),mp(x,(fd-1)->Y))),*fd=mp(a[x],(fd-1)->Y);
    	fd=lower_bound(dp_i[x].begin(),dp_i[x].end(),mp(a[x],inf),greater<pair<int,int> >());
    	ans[x]=max(ans[x],mp(int(fd-dp_i[x].begin()),mp(x,(fd-1)->Y))),*fd=mp(a[x],(fd-1)->Y);
    	tot[x]=max(tot[x],ans[x]);
    //	for(int i=1;i<=mxdep[x];i++)assert(dp_d[x][i].X==inf||dp_d[x][i].Y);
    //	cout<<x<<" "<<ans[x].X<<"!
    ";
    //	cout<<x<<" 's i: ";for(int i=1;i<=mxdep[x];i++)cout<<dp_i[x][i].X<<","<<dp_i[x][i].Y<<" ";puts("");
    //	cout<<x<<" 's d: ";for(int i=1;i<=mxdep[x];i++)cout<<dp_d[x][i].X<<","<<dp_d[x][i].Y<<" ";puts("");
    }
    void deal(int x){
    	assert(x);
    	memset(dson,0,sizeof(dson));for(int i=1;i<=n;i++)dp_i[i].clear(),dp_d[i].clear();
    	dfs1(x);
    	dfs2(x);
    }
    vector<int> v;
    bool upd[N];
    void dfs0(int x,int aim,int fa=0){
    	v.pb(x);
    	if(x==aim)for(int i=0;i<v.size();i++)upd[v[i]]=true;
    	for(int i=0;i<nei[x].size();i++){
    		int y=nei[x][i];
    		if(y==fa)continue;
    		dfs0(y,aim,x);
    	}
    	v.pop_back();
    }
    int main(){
    	freopen("lis.in","r",stdin);freopen("lis.out","w",stdout);
    	cin>>n;
    	for(int i=1;i<n;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		nei[x].pb(y),nei[y].pb(x);
    	}
    	for(int i=1;i<=n;i++)scanf("%d",a+i);
    	deal(1);
    	pair<int,pair<int,int> > mx=tot[1];
    	int x=mx.Y.X,y=mx.Y.Y;
    //	cout<<x<<" "<<y<<" "<<mx.X<<"!
    ";
    	dfs0(x,y);
    	deal(x),deal(y);
    	int out=inf;
    	for(int i=1;i<=n;i++)if(upd[i])out=min(out,rl[i]);
    	cout<<out<<"
    ";
    	return 0;
    }
    
    珍爱生命,远离抄袭!
  • 相关阅读:
    【JavaScript】WebBrowser控件下IE版本的检测
    【ArcGIS】Oracle RAC下创建地理数据库(Create Enterprise Geodatabase)失败的解决方法
    【IOS】从零开始搭建基于Xcode7的IOS开发环境和免开发者帐号真机调试运行第一个IOS程序HelloWorld
    【Delphi】解决Delphi Distiller运行报错"HKEY_CURRENT_USER\" is of wrong kind or size
    【Oracle】根据字段值全库搜索相关数据表和字段
    【Android】彻底去除Google AdMob广告
    【Android】豆瓣FM离线数据
    【Android】反编译apk + eclipse中调试smali
    关于React前端构建的一般过程
    Consul入门
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/solution-nfls20034-12449.html
Copyright © 2011-2022 走看看