题目:给你一颗树,然后n个点,n-1条边.然后给你q组查询,每组查询给你三个数分别是:u,v,c 题目保证1是首都,并且u->v->1这种类型的查询.问你从u->v的最长上升子序列长度..
接下来我来解说下题解吧,hhh,因为我不会,tcl..给题解增添细节;
题解的思路是 类似rmq的东西+二进制查找(自命名hhh)
一段代码一段代码来...保证萌新都懂~
因为查询是固定顺序的..所以是个有向图..其他代码照搬题解代码解释一下,然后大家自己敲一次吧~

 scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for (int i = 1; i < n; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        v[x].push_back(y);
    }

这段代码是输入每个点自带的权值,然后联通x<-y的路线

for (int i = n + 1; i <= n + q; i++)
    {
        int x, y, c;
        scanf("%d%d%d", &x, &y, &c);
        v[x].push_back(i);
        a[i] = c;
        to[i - n] = y;   //记录对应的终点
    }

这段代码是把q组输入的值存起来..考虑前面的点都是在1~n的范围内,我们创建新点在(n+1,n+q)把我们要查询的点变成新的节点放到x节点上,然后新的节点也自带权值,刚好符合题目进行查询..这个假如不懂可以先看后面的,看了后面的应该就懂了.

dfs(1, 0);
void dfs(int p, int fa)
{
    int x = fa;
    for (int k = 19; k >= 0; k--)
    if (f[x][k] && a[f[x][k]] <= a[p] ) x = f[x][k];   //如果x往上跳2^k步这个点存在,且这个点的权值比a[p]要小,就跳到这个点再往上跳
    if (a[x] > a[p]) f[p][0] = x;  //判断比a[p]大的点到底是x还是x的上面那个点
    else f[p][0] = f[x][0];
    //向上倍增的找到第一个比p权值大的点
    for (int i = 1; i < 20; i++) f[p][i] = f[f[p][i - 1]][i - 1];  //倍增的求出每个点向上2^j步的点
    dep[p] = dep[fa] + 1;   //维护高度
    int num = v[p].size();
    for (int i = 0; i < num; i++)
    {
        int to = v[p][i];
        dfs(to, p);   //搜儿子
    }
}

首先解释下f数组的含义,f[i][j]表示的i后面2^j后递增数列的值是多少..比方说1 3 4 5 6 2 8假如我的i是1,f[1][0]就是比它大2^0的位子的值,也就是3,f[1][1]那就是比它大2^1的位子的值,也就是4..再解释下p,fa,p是我当前搜询的这个节点,fa是我搜寻的那个节点的上一个节点..搜寻是从根节点到子节点慢慢来的..dep是记录我在那一层.比如我的树是一条链1<-2<-3<-5那么dep[1]=1;dep[2]=2;dep[3]=3;dep[5]=4;数组变量解释完了,dfs这个不懂那先别做这题..
x是找到第一个大于fa的节点..也就是f[fa][0];
下面我来解释这段代码:

for (int k = 19; k >= 0; k--)
    if (f[x][k] && a[f[x][k]] <= a[p] ) x = f[x][k];

大家都知道二进制可以表示任何十进制的数,这个也是一样的,不过是用二进制表示十进制位子所处的位子,假如我那个位子离我们11,我们应该怎么找到它呢?我们把11二进制分解就是1011那么我先找到第一位的1也就是8,第二位的1不能取哦..取了就是12了嘛~然后3,4位也取1就好了..解释下为什么要倒着取..就是准确的确定一个数必定要倒着取,因为你正着取,比如还是11,正着取,第一次取1,第二次我又取1,第三次我还是取1,7了,而第四个我就不能取了..这段代码解释完了..

f (a[x] > a[p]) f[p][0] = x;  
    else f[p][0] = f[x][0];

这段代码就比较简单了,就是确定f[p][0]的位子,假如大于fa节点的值假如不存在/存在..那么我就是比较下a[fa]和a[p]的大小..假如大于fa节点的第一个值/a[fa]小于a[p],那么肯定那个值是f[x][0]..而且是递归来的,那么上个转态的f[x][0]是存在的..这段代码解释完了..

    for (int i = 1; i < 20; i++) f[p][i] = f[f[p][i - 1]][i - 1];  

这段代码的总用就是通过前面的状态和f[p][0]更新这个状态的全部状态..好吧,这里也给萌新详细解释一下..先解释下状态方程f[p][i] = f[f[p][i - 1]][i - 1],现在我的状态是p,那么我现在要求p递增序列的第2^i个是不是等于我求p后面2^(i-1)个再求2^(i-1)个?我现在知道了f[p][0]和f[<p][<20]那么我是不是就可以把现在的状态全部转移完了呢?

dep[p] = dep[fa] + 1;

这句话是求深度..也就是位于树的第几层..

    int num = v[p].size();
    for (int i = 0; i < num; i++)
    {
        int to = v[p][i];
        dfs(to, p);   //搜儿子
    }

这句话的意思就是搜儿子,找下一个点..
dfs部分是为了打一张表..一张知道所有点->到2^i(i<=19)的表..
接下来这部分代码是查询记录答案..

for (int i = 1; i <= q; i++)
    {
        int ans = 0;
        int x = i + n;   //i+n是第i个询问的起点
        for (int k = 19; k >= 0; k--)   //k从大到小枚举
            if (dep[f[x][k]] >= dep[to[i]])   //如果跳完之后深度小于目标点深度就已经走过了,跳跃高度要减小
            {
                ans += (1 << k);           //点数加2^k
                x = f[x][k];               //向上跳2^k个点
            }
        printf("%d\n", ans);
    }

这里的原理楼上介绍过了..我就不详细再重复一次了..ans每次查询先赋值为0..然后跳深度每次跳到比它大的地方,也就是楼上介绍的二进制..然后每次跳的是2^k答案就+2^k..
ac代码:

#include<bits/stdc++.h>
#define ios ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define pb push_back
#define inf 132913423039
typedef long long ll;
const ll mod=1e9+7;
const ll N=1e6+5;
const double eps=1e-7;
using namespace std;
const int manx=1e7+5;
ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b) { return a*b/gcd(a,b);    }
ll qp(ll a,ll b, ll p){ll ans = 1;while(b){if(b&1){ans = (ans*a)%p;--b;}a = (a*a)%p;b >>= 1;}return ans%p;}
ll Inv(ll x)          { return qp(x,mod-2,mod);}
ll C(ll n,ll m){if (m>n) return 0;ll ans = 1;for (int i = 1; i <= m; ++i) ans=ans*Inv(i)%mod*(n-i+1)%mod;return ans%mod;}
vector<int> v[N];
int a[N], f[N][20], dep[N], to[N];
void dfs(int p, int fa)
{
    int x = fa;
    for (int k = 19; k >= 0; k--)
    if (f[x][k] && a[f[x][k]] <= a[p] ) x = f[x][k];   //如果x往上跳2^k步这个点存在,且这个点的权值比a[p]要小,就跳到这个点再往上跳
    if (a[x] > a[p]) f[p][0] = x;  //判断比a[p]大的点到底是x还是x的上面那个点
    else f[p][0] = f[x][0];
    //向上倍增的找到第一个比p权值大的点

    for (int i = 1; i < 20; i++) f[p][i] = f[f[p][i - 1]][i - 1];  //倍增的求出每个点向上2^j步的点

    dep[p] = dep[fa] + 1;   //维护高度

    int num = v[p].size();
    for (int i = 0; i < num; i++)
    {
        int to = v[p][i];
        dfs(to, p);   //搜儿子
    }
}
int n, q;
int main()
{
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for (int i = 1; i < n; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        v[x].push_back(y);
    }
    for (int i = n + 1; i <= n + q; i++)
    {
        int x, y, c;
        scanf("%d%d%d", &x, &y, &c);
        v[x].push_back(i);
        a[i] = c;
        to[i - n] = y;   //记录对应的终点
    }
    dfs(1, 0);
    for (int i = 1; i <= q; i++)
    {
        int ans = 0;
        int x = i + n;   //i+n是第i个询问的起点
        for (int k = 19; k >= 0; k--)   //k从大到小枚举
            if (dep[f[x][k]] >= dep[to[i]])   //如果跳完之后深度小于目标点深度就已经走过了,跳跃高度要减小
            {
                ans += (1 << k);           //点数加2^k
                x = f[x][k];               //向上跳2^k个点
            }
        printf("%d\n", ans);
    }
    return 0;
}

完结撒花~