【题意】求树上任意两点u->v的LIS;
【分析】可以用树链剖分,不过最近在练LCT,就用LCT来写,维护区间信息很简单,只要注意下LCT最后求上来的时候是lca->u,lca->v,lca;所以需要维护一个从后往前的LIS值。第一次写LCT 1A,好开心(七夕宅在家调了一上午,有点郁闷)。
【AC CODE】1201ms
#include <bits/stdc++.h> using namespace std; typedef long long LL; #define rep(i,a,n) for(int i = a; i < n; i++) #define repe(i,a,n) for(int i = a; i <= n; i++) #define per(i,n,a) for(int i = n; i >= a; i--) #define clc(a,b) memset(a,b,sizeof(a)) #define ls ch[u][0] #define rs ch[u][1] const int INF = 0x3f3f3f3f, MAXN = 100000+10; int par[MAXN],fa[MAXN],ch[MAXN][2],val[MAXN]; int mx[MAXN][2],lsum[MAXN][2],lv[MAXN],rsum[MAXN][2],rv[MAXN],sz[MAXN]; void init() { clc(par,0);clc(fa,0);clc(ch,0); } inline int chd(int u){return ch[fa[u]][1] == u;} inline void setch(int f, int u, int d){ch[f][d] = u, fa[u] = f;} inline void push_up(int u) { //l->r mx[u][0] = max(mx[ls][0],mx[rs][0]); if(!ls || rv[ls] < val[u]) { mx[u][0] = max(mx[u][0],rsum[ls][0]+1); if(val[u] < lv[rs]) mx[u][0] = max(mx[u][0],rsum[ls][0]+1+lsum[rs][0]); } if(val[u] < lv[rs]) mx[u][0] = max(mx[u][0],1+lsum[rs][0]); lsum[u][0] = lsum[ls][0]; if(lsum[ls][0] == sz[ls]) { if(!ls || rv[ls] < val[u]) { lsum[u][0]++; if(val[u] < lv[rs]) lsum[u][0] += lsum[rs][0]; } } rsum[u][0] = rsum[rs][0]; if(rsum[rs][0] == sz[rs]) { if(!rs || val[u] < lv[rs]) { rsum[u][0]++; if(rv[ls] < val[u]) rsum[u][0] += rsum[ls][0]; } } //r->l mx[u][1] = max(mx[ls][1],mx[rs][1]); if(!rs || lv[rs] < val[u]) { mx[u][1] = max(mx[u][1],lsum[rs][1]+1); if(val[u] < rv[ls]) mx[u][1] = max(mx[u][1],lsum[rs][1]+1+rsum[ls][1]); } if(val[u] < rv[ls]) mx[u][1] = max(mx[u][1],1+rsum[ls][1]); lsum[u][1] = lsum[ls][1]; if(lsum[u][1] == sz[ls]) { if(!ls || val[u] < rv[ls]) { lsum[u][1]++; if(lv[rs] < val[u]) lsum[u][1] += lsum[rs][1]; } } rsum[u][1] = rsum[rs][1]; if(rsum[u][1] == sz[rs]) { if(!rs || lv[rs] < val[u]) { rsum[u][1]++; if(val[u] < rv[ls]) rsum[u][1] += rsum[ls][1]; } } lv[u] = ls?lv[ls]:val[u],rv[u] = rs?rv[rs]:val[u]; sz[u] = sz[ls]+sz[rs]+1; } inline void rot(int u) { int d = chd(u),y = fa[u]; setch(fa[y],u,chd(y)); setch(y,ch[u][d^1],d); setch(u,y,d^1); push_up(y);push_up(u); } void splay(int u) { int rt = u; while(fa[rt]) rt = fa[rt]; if(rt == u) return; par[u] = par[rt],par[rt] = 0; while(fa[u]) { if(fa[fa[u]] && chd(u) == chd(fa[u])) rot(fa[u]); rot(u); } } void expose(int u) { for(int now = u,la = 0;now;la = now,now = par[now]) { splay(now); par[ch[now][1]] = now;fa[ch[now][1]] = par[la] = 0; setch(now,la,1); push_up(now); } splay(u); } int query(int u, int v) { expose(u); for(int now = v,la = 0;now;la = now,now = par[now]) { splay(now); if(!par[now]) { int l = ch[now][1],r = la; int ans = max(max(mx[l][1],mx[r][0]),1); if(lv[l] < val[now]) { ans = max(ans,lsum[l][1]+1); if(val[now] < lv[r]) ans = max(ans,lsum[l][1]+1+lsum[r][0]); } if(val[now] < lv[r]) ans = max(ans,1+lsum[r][0]); return ans; } par[ch[now][1]] = now;fa[ch[now][1]] = par[la] = 0; setch(now,la,1); push_up(now); } } int main() { #ifdef SHY freopen("d:\\1.txt", "r", stdin); #endif int t,count = 0; scanf("%d", &t); while(t--) { init(); int n; scanf("%d", &n); repe(i,1,n) { scanf("%d", &val[i]); lv[i] = rv[i] = val[i]; mx[i][0] = mx[i][1] = lsum[i][0] = lsum[i][1] = rsum[i][0] = rsum[i][1] = sz[i] = 1; } repe(i,2,n) scanf("%d", &par[i]); int q; if(count++) putchar('\n'); printf("Case #%d:\n",count); scanf("%d", &q); while(q--) { int u,v; scanf("%d %d", &u, &v); printf("%d\n", query(u,v)); } } return 0; }