[Feyat Cup 1.0][JZOJ3338]法法塔的奖励
2016-03-09 19:47
381 查看
题目大意
给定一棵n个节点的树,每个点有一个权值vi。对于以x为根的子树,我们要从中找出一条从叶子节点到x的路径,将所有权值按顺序排列,求其最长不下降子序列(点x一定要选),所有这种路径中最长的最长不下降子序列长度即为该子树答案。
求以每一个节点为根的子树的答案。
1≤vi≤n≤105
题目分析
显然我们需要递归处理子树,合并所有儿子子树的信息,更新当前子树答案。考虑使用什么数据结构维护最长不下降子序列,我们可以用权值线段树、平衡树等等。
然后合并所有儿子上的数据结构,更新答案即可。
我使用的是权值线段树,合并时直接合并即可。至于线段树合并为什么是O(nlog2n)的我也不会证。
具体细节见代码实现。
代码实现
#include <iostream> #include <cstdio> #include <cctype> using namespace std; int read() { int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); } while (isdigit(ch)) { x=x*10+ch-'0'; ch=getchar(); } return x*f; } int buf[20]; void write(int x) { if (x<0) putchar('-'),x=-x; buf[0]=0; while (x) { buf[++buf[0]]=x%10; x/=10; } if (!buf[0]) buf[++buf[0]]=0; while (buf[0]) putchar(buf[buf[0]--]+'0'); } const int N=100050; const int L=100000; const int S=N*20; struct segment_tree { int v[S],son[S][2],root ; int tot; int merge(int rt1,int rt2,int l,int r) { if (!(1ll*rt1*rt2)) return rt1+rt2; v[rt1]=max(v[rt1],v[rt2]); if (l==r) return rt1; int mid=l+r>>1; son[rt1][0]=merge(son[rt1][0],son[rt2][0],l,mid); son[rt1][1]=merge(son[rt1][1],son[rt2][1],mid+1,r); return rt1; } int query(int rt,int st,int en,int l,int r) { if (!rt) return 0; if (l==st&&r==en) return v[rt]; int mid=l+r>>1; if (en<=mid) return query(son[rt][0],st,en,l,mid); else if (mid+1<=st) return query(son[rt][1],st,en,mid+1,r); else return max(query(son[rt][0],st,mid,l,mid),query(son[rt][1],mid+1,en,mid+1,r)); } int change(int rt,int y,int l,int r,int edit) { if (!rt) rt=++tot; if (l==r) { v[rt]=max(edit,v[rt]); return rt; } int mid=l+r>>1; if (y<=mid) son[rt][0]=change(son[rt][0],y,l,mid,edit); else son[rt][1]=change(son[rt][1],y,mid+1,r,edit); v[rt]=max(v[son[rt][0]],v[son[rt][1]]); return rt; } }t; int ans ,fa ,last ,next ,tov ,val ; int tot,n; void insert(int x,int y) { tov[++tot]=y; next[tot]=last[x]; last[x]=tot; } void dfs(int x) { int i=last[x],y,rt=0; while (i) { y=tov[i]; dfs(y); rt=t.merge(rt,t.root[y],1,L); i=next[i]; } ans[x]=t.query(rt,1,val[x],1,L)+1; t.root[x]=t.change(rt,val[x],1,L,ans[x]); } int main() { freopen("reward.in","r",stdin); freopen("reward.out","w",stdout); n=read(); read(); for (int i=2;i<=n;i++) fa[i]=read(),insert(fa[i],i); for (int i=1;i<=n;i++) val[i]=read(); dfs(1); for (int i=1;i<=n;i++) write(ans[i]),putchar(i!=n?' ':'\n'); fclose(stdin); fclose(stdout); return 0; }
相关文章推荐
- 炫酷的jQuery对话框插gDialog
- js过滤空格
- Angular的run方法巧妙运用
- Java中的stringbuffer和String类:
- JavaScript 原型概念深入理解
- Html学习笔记(3)-Html标签(2)
- Html学习笔记(4)-Html标签(3)
- Html学习笔记(5)-Html标签(4)
- Html学习笔记(6)-与浏览者交互,表单标签
- Html学习笔记(1)-Html初步
- Web前端学习笔记(3)-html5新增表单元素
- 《剑指offer》——数组中重复的数字
- css限制显示字数,文字长度超出部分用省略号表示
- 用jQuery创建HTML中不存在的标签元素碰到的问题
- TypeScript Type Innference(类型推断)
- JS总结
- BootStrap入门_创建第一个例子
- js实现页面跳转,location.href和location.replace和location.reload的区别
- html5 式程序员表白
- 如何使用JS编写一个简单的计算器