题意给你q次询问,给一条链问从给定起点到给定终点的最长连续严格递增子序列。
因为给定起点与终点所以路径可能与dfs序的树节点展开顺序相反。所以问题变成了给n个数询问一个区间的最长LCIS。
但因为方向可正可负,所以我们除了维护区间的最长递增以外还要维护最长递减。线段树的部分就做完了。
树链剖分的时候进行线段树合并,合并的时候右区间取前一个区间,左区间取当前区间。要注意从起点出发的链取最长递减,从终点出发的取最长递增。
当他们来到一条链时,当x比y 的深度更浅这时应该将这段长度与y合并,y比x浅时应该将长度与x合并。因为链都是向上合并的,不能向下合并。
最后将起点的最长递减与终点的最长递增比较,如果起点合并后的左端点小于终点合并后的左端点就将起点区间的左长度与终点区间的左长度加起来更新答案。
对拍大法好!!
#include <bits/stdc++.h> #define Lson l,mid,rt<<1 #define Rson mid+1,r,rt<<1|1 using namespace std; const int M = 1e5+7; int _,n,q,a[M]; int head[M],cnt,tot,tmp,cas=1; int sz[M],f[M],dep[M],son[M],rnk[M],top[M],id[M]; struct edge { int v,next; }e[M<<1]; struct Tree { int len; int lnum,rnum; int inl,inr,in; int del,der,de; }tree[M<<3]; void init(){ cnt=tot=0;memset(head,-1,sizeof(head)); } void add(int u,int v){ e[++cnt].v=v;e[cnt].next=head[u]; head[u]=cnt; } void dfs(int u,int fa,int d){ sz[u]=1;son[u]=-1;f[u]=fa;dep[u]=d; for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==fa) continue; dfs(v,u,d+1); sz[u]+=sz[v]; if(son[u]==-1||sz[v]>sz[son[u]]) son[u]=v; } return ; } void dfs1(int u,int t){ id[u]=++tot; rnk[tot]=u; top[u]=t; if(son[u]==-1) return ; dfs1(son[u],t); for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(v==f[u]||v==son[u]) continue; dfs1(v,v); } return ; } void Pushup(int rt,int l,int r){ tree[rt].len=tree[l].len+tree[r].len; tree[rt].lnum=tree[l].lnum; tree[rt].rnum=tree[r].rnum; tree[rt].inl=tree[l].inl; tree[rt].inr=tree[r].inr; tree[rt].in=max(tree[l].in,tree[r].in); tree[rt].del=tree[l].del; tree[rt].der=tree[r].der; tree[rt].de=max(tree[l].de,tree[r].de); if(tree[l].rnum<tree[r].lnum){ if(tree[l].inl==tree[l].len) tree[rt].inl+=tree[r].inl; tree[rt].in=max(tree[rt].in,tree[rt].inl); if(tree[r].inr==tree[r].len) tree[rt].inr+=tree[l].inr; tree[rt].in=max(tree[rt].in,tree[rt].inr); tree[rt].in=max(tree[rt].in,tree[l].inr+tree[r].inl); } if(tree[l].rnum>tree[r].lnum){ if(tree[l].del==tree[l].len) tree[rt].del+=tree[r].del; tree[rt].de=max(tree[rt].de,tree[rt].del); if(tree[r].der==tree[r].len) tree[rt].der+=tree[l].der; tree[rt].de=max(tree[rt].de,tree[rt].der); tree[rt].de=max(tree[rt].de,tree[l].der+tree[r].del); } } void build(int l,int r,int rt){ if(l==r){ tree[rt].lnum=tree[rt].rnum=a[rnk[l]];tree[rt].len=1; tree[rt].inl=tree[rt].inr=tree[rt].del=tree[rt].der=tree[rt].de=tree[rt].in=1; return; } int mid=(l+r)>>1; build(Lson); build(Rson); Pushup(rt,rt<<1,rt<<1|1); } int query(int L,int R,int l,int r,int rt){ if(L==l&&r==R){ return rt; } int mid=(l+r)>>1; if(L>mid) return query(L,R,Rson); else if(R<=mid) return query(L,R,Lson); else{ int ll=query(L,mid,Lson),rr=query(mid+1,R,Rson); Pushup(++tmp,ll,rr); return tmp; } } int sum(int x,int y){ int fx=top[x],fy=top[y];tmp=M<<2; int xl,xr=-1,yl,yr=-1; while(fx!=fy){ if(dep[fx]>dep[fy]){ xl=query(id[fx],id[x],1,n,1); if(xr==-1) xr=xl; else{ Pushup(++tmp,xl,xr);xr=tmp; } x=f[fx],fx=top[x]; } else{ yl=query(id[fy],id[y],1,n,1); //cout<<tree[yl].lnum<<endl; if(yr==-1) yr=yl; else{ Pushup(++tmp,yl,yr);yr=tmp; } y=f[fy],fy=top[y]; } //cout<<fx<<" "<<fy<<" "<<tree[yr].de<<endl; } if(dep[x]<dep[y]){ yl=query(id[x],id[y],1,n,1); if(yr==-1) yr=yl; else{ Pushup(++tmp,yl,yr);yr=tmp; } } else{ xl=query(id[y],id[x],1,n,1); if(xr==-1) xr=xl; else{ Pushup(++tmp,xl,xr);xr=tmp; } } if(xr==-1) return tree[yr].in; if(yr==-1) return tree[xr].de; int res; //cout<<tree[xr].de<<" "<<tree[yr].in<<endl; res=max(tree[xr].de,tree[yr].in); if(tree[xr].lnum<tree[yr].lnum){ res=max(res,tree[xr].del+tree[yr].inl); } return res; } int main(){ scanf("%d",&_); while(_--){ init(); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=2;i<=n;i++){ int u; scanf("%d",&u); add(u,i);add(i,u); } dfs(1,-1,1);dfs1(1,1); build(1,n,1); scanf("%d",&q); printf("Case #%d:\n",cas++); while(q--){ int from,to; scanf("%d%d",&from,&to); printf("%d\n",sum(from,to)); } if(_) printf("\n"); } return 0; }
原文地址:https://www.cnblogs.com/LMissher/p/9551637.html
时间: 2024-10-15 16:24:54