码迷,mamicode.com
首页 > 其他好文 > 详细

[CF490F]Treeland Tour(线段树合并)

时间:2019-03-22 00:42:54      阅读:140      评论:0      收藏:0      [点我收藏+]

标签:col   ++   pre   线段树   ret   for   mes   print   using   

树上LIS:树上找一条简单路径的子序列使点权严格单增,最大化长度。

原题数据过小,用线段树合并可以做到$O(n\log n)$。

每个点用一棵线段树维护以每个权值为结尾的LIS最长长度,线段树合并时更新子序列不包含当前点时的最大值,再线段树上区间询问得到包含时的最大值并更新线段树。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define lson ls[x],L,mid
 4 #define rson rs[x],mid+1,R
 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 6 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
 7 using namespace std;
 8 
 9 const int N=100010;
10 int n,u,v,ans,nd,cnt,tot,lis[N*25],lds[N*25],ls[N*25],rs[N*25];
11 int h[N],to[N<<1],nxt[N<<1],rt[N],a[N],b[N];
12 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
13 
14 int merge(int x,int y){
15     if (!x || !y) return x|y;
16     lis[x]=max(lis[x],lis[y]); lds[x]=max(lds[x],lds[y]);
17     ans=max(ans,max(lis[ls[x]]+lds[rs[y]],lds[rs[x]]+lis[ls[y]]));
18     ls[x]=merge(ls[x],ls[y]); rs[x]=merge(rs[x],rs[y]); return x;
19 }
20 
21 void mdf(int &x,int L,int R,int p,int k,int a[]){
22     if (!x) x=++nd;
23     a[x]=max(a[x],k); int mid=(L+R)>>1;
24     if (L==R) return;
25     if (p<=mid) mdf(lson,p,k,a); else mdf(rson,p,k,a);
26 }
27 
28 int que(int x,int L,int R,int l,int r,int a[]){
29     if (L==l && r==R) return a[x];
30     int mid=(L+R)>>1;
31     if (r<=mid) return que(lson,l,r,a);
32     else if (l>mid) return que(rson,l,r,a);
33         else return max(que(lson,l,mid,a),que(rson,mid+1,r,a));
34 }
35 
36 void dfs(int x,int fa){
37     For(i,x) if ((k=to[i])!=fa) dfs(k,x);
38     int s1=0,s2=0,t1,t2;
39     For(i,x) if ((k=to[i])!=fa){
40         t1=a[x]>1 ? que(rt[k],1,tot,1,a[x]-1,lis) : 0;
41         t2=a[x]<tot ? que(rt[k],1,tot,a[x]+1,tot,lds) : 0;
42         rt[x]=merge(rt[x],rt[k]); ans=max(ans,max(s1+t2+1,s2+t1+1));
43         s1=max(s1,t1); s2=max(s2,t2);
44     }
45     mdf(rt[x],1,tot,a[x],s1+1,lis); mdf(rt[x],1,tot,a[x],s2+1,lds);
46 }
47 
48 int main(){
49     freopen("490F.in","r",stdin);
50     freopen("490F.out","w",stdout);
51     scanf("%d",&n);
52     rep(i,1,n) scanf("%d",&a[i]),b[i]=a[i];
53     sort(b+1,b+n+1); tot=unique(b+1,b+n+1)-b-1;
54     rep(i,1,n) a[i]=lower_bound(b+1,b+tot+1,a[i])-b;
55     rep(i,2,n) scanf("%d%d",&u,&v),add(u,v),add(v,u);
56     dfs(1,0); printf("%d\n",ans);
57     return 0;
58 }

 

[CF490F]Treeland Tour(线段树合并)

标签:col   ++   pre   线段树   ret   for   mes   print   using   

原文地址:https://www.cnblogs.com/HocRiser/p/10575651.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!