题意:给你一棵带点权的树,问树上两点间的LCIS(最长持续严格上升序列)
题解:树链剖分+线段树合并
不会线段树合并可以先做3308
因为是要从u到v的LCIS这里是有个方向关系的
需要维护从下往上的,也需要从上往下的
所以我建了两颗线段树
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define PB push_back
#define MP make_pair
#define ll long long
#define MS(a,b) memset(a,b,sizeof(a))
#define LL (rt<<1)
#define RR (rt<<1|1)
#define lson l,mid,LL
#define rson mid+1,r,RR
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lb(x) (x&(-x))
void In(){freopen("in.in","r",stdin);}
void Out(){freopen("out.out","w",stdout);}
const int N=1e5+10;
const int M=3e5+10;
const int Mbit=1e6+10;
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
int NE,id;
int head[N],dep[N],son[N],siz[N],father[N],top[N],tid[N],mark[N];
struct Edge
{
int v,next;
}edge[N<<1];
void init(int n)
{
NE=0;
for(int i=1;i<=n;i++)head[i]=-1;
}
void add(int u,int v)
{
edge[NE].v=v;
edge[NE].next=head[u];
head[u]=NE++;
}
void dfs1(int u,int fa)
{
dep[u]=dep[fa]+1;
son[u]=0;
father[u]=fa;
siz[u]=1;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
if(v==fa)continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v])son[u]=v;
}
}
void dfs2(int u,int fa)
{
tid[u]=id++;
mark[tid[u]]=u;
top[u]=fa;
if(son[u]!=0)dfs2(son[u],fa);
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
if(v==father[u]||v==son[u])continue;
dfs2(v,v);
}
}
int a[N],n;
struct node
{
int l,r,lsum,rsum,msum,len;
}tree[N<<2],tr[N<<2];
node Merge(node t1,node t2)
{
if(t1.l==-1)return t2;
if(t2.l==-1)return t1;
node t;
t.len=t1.len+t2.len;
t.l=t1.l;
t.r=t2.r;
t.lsum=t1.lsum+((t1.lsum==t1.len&&t1.r<t2.l)?t2.lsum:0);
t.rsum=t2.rsum+((t2.rsum==t2.len&&t1.r<t2.l)?t1.rsum:0);
t.msum=max(t1.msum,t2.msum);
if(t1.r<t2.l)
t.msum=max(t.msum,t1.rsum+t2.lsum);
return t;
}
void up(int rt)
{
tree[rt]=Merge(tree[LL],tree[RR]);
}
void up1(int rt)
{
tr[rt]=Merge(tr[LL],tr[RR]);
}
void build(int l,int r,int rt)
{
tree[rt].len=r-l+1;
if(l==r){
tree[rt].l=tree[rt].r=a[mark[l]];
tree[rt].lsum=tree[rt].rsum=tree[rt].msum=1;
return;
}
int mid=l+r>>1;
build(lson);
build(rson);
up(rt);
}
void build1(int l,int r,int rt)
{
tr[rt].len=r-l+1;
if(l==r){
tr[rt].l=tr[rt].r=a[mark[n-l+1]];
tr[rt].lsum=tr[rt].rsum=tr[rt].msum=1;
return;
}
int mid=l+r>>1;
build1(lson);
build1(rson);
up1(rt);
}
node query1(int l,int r,int rt,int L,int R)
{
if(L<=l&&r<=R)return tr[rt];
node t,t1,t2;
t1.l=-1;t2.l=-1;
int mid=l+r>>1;
if(L<=mid)t1=query1(lson,L,R);
if(R>mid) t2=query1(rson,L,R);
return Merge(t1,t2);
}
node query(int l,int r,int rt,int L,int R)
{
if(L<=l&&r<=R)return tree[rt];
node t,t1,t2;
t1.l=-1;t2.l=-1;
int mid=l+r>>1;
if(L<=mid)t1=query(lson,L,R);
if(R>mid) t2=query(rson,L,R);
return Merge(t1,t2);
}
node color(int u,int v)
{
int flag=0;
node ans1,ans2;
ans1.l=-1;ans2.l=-1;
while(top[u]!=top[v]){
if(dep[top[u]]>dep[top[v]])swap(u,v),flag^=1;
if(flag==1)
ans1=Merge(ans1,query1(1,n,1,n-tid[v]+1,n-tid[top[v]]+1));
else
ans2=Merge(query(1,n,1,tid[top[v]],tid[v]),ans2);
v=father[top[v]];
}
if(tid[u]>tid[v])swap(u,v),flag^=1;
if(flag==0)
ans1=Merge(ans1,query(1,n,1,tid[u],tid[v]));
else
ans2=Merge(query1(1,n,1,n-tid[v]+1,n-tid[u]+1),ans2);
return Merge(ans1,ans2);
}
int main()
{
//In();
int T,kase=0,q;
scanf("%d",&T);
while(T--){
printf("Case #%d:\n",++kase);
scanf("%d",&n);
init(n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=2;i<=n;i++){
int x;scanf("%d",&x);
add(x,i);
}
siz[0]=dep[1]=0;id=1;
dfs1(1,1);
dfs2(1,1);
build(1,n,1);
build1(1,n,1);
scanf("%d",&q);
for(int i=1;i<=q;i++){
int u,v;
scanf("%d%d",&u,&v);
printf("%d\n",color(u,v).msum);
}
if(T)puts("");
}
return 0;
}