JZOJ 3338. 【NOI2013模拟】法法塔的奖励

D e s c r i p t i o n Description Description

树上 L C S LCS LCS,强制根必须在 L C S LCS LCS

数据范围: n l o g n nlogn nlogn


S o l u t i o n Solution Solution

md要不是最后那句话我这道题绝对是最快最优解,艹

首先这就是一道二维偏序嘛(一维是权值,另一维是 d f n dfn dfn),所以我们按 d f s dfs dfs序做 L C S LCS LCS就行了啦

那第二个限制条件咋搞?

先查询,再放入根,就保证了啦QwQ

时间复杂度?疑似 O ( n l o g n ) O(nlogn) O(nlogn)然而理论上 O ( n 2 l o g n ) O(n^2logn) O(n2logn),实际上远远达不到呀2333

当然你也可以打启发式合并就稳稳的双log了2333


C o d e Code Code

#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include
#include
#include
#include
#include
#define N 100010
using namespace std;int n,fa[N],a[N],m,ans[N],tot;
vector<int>son[N];
inline long long read()
{
	char c;int f=0,d=1;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
struct xds
{
	int ls[N*200],rs[N*200],sum[N*200],rt[N];
	inline int merge(int a,int b,int l=1,int r=n)
	{
		if(!a||!b) return a^b;
		sum[a]=max(sum[a],sum[b]);
		if(l==r) return a;
		int mid=l+r>>1;
		ls[a]=merge(ls[a],ls[b],l,mid);
		rs[a]=merge(rs[a],rs[b],mid+1,r);
		return a;
	}
	inline void insert(int &o,int pos,int val,int l=1,int r=n)
	{
		if(!o) o=++tot;
		sum[o]=max(sum[o],val);
		if(l==r) return;
		int mid=l+r>>1;
		if(pos<=mid) insert(ls[o],pos,val,l,mid);
		else insert(rs[o],pos,val,mid+1,r);
		return;
	}
	inline int query(int o,int ql,int qr,int l=1,int r=n)
	{
		if(!o) return 0;
		if(l>=ql&&r<=qr) return sum[o];
		int mid=l+r>>1,ans=-1;
		if(ql<=mid) ans=query(ls[o],ql,qr,l,mid);
		if(qr>mid) ans=max(ans,query(rs[o],ql,qr,mid+1,r));
		return ans;
	}
}tree;
inline void dfs(int x,int fa)
{
	for(register int i=0;i<son[x].size();i++)
	{
		int y=son[x][i];
		if(y==fa) continue;
		dfs(y,fa);
		tree.rt[x]=tree.merge(tree.rt[x],tree.rt[y]);
	}
	ans[x]=tree.query(tree.rt[x],1,a[x])+1;
	tree.insert(tree.rt[x],a[x],ans[x]);
	return;
}
signed main()
{
	n=read();read();
	for(register int i=2;i<=n;i++) fa[i]=read(),son[fa[i]].push_back(i);
	for(register int i=1;i<=n;i++) a[i]=read();
	dfs(1,0);
	for(register int i=1;i<=n;i++) printf("%d ",ans[i]);
}

你可能感兴趣的:(线段树,平衡树,单调队列,CDQ分治,JZOJ,3338,NOI2013模拟,法法塔的奖励)