题意:

一个树,对其有两个操作,操作1是将节点a的权值增加x
操作2是查询节点a到根节点R的简单路径上所有节点的权值的平方的和
答案对2^取模

题解:

如果ull类型的整数溢出了,就相当于取模2^64了。因为ull的范围是[0,2^64-1],所以直接开unsigned long long就行
有两个方法:
1.树链剖分单点修改,树链查询,时间复杂度为O(nlognlogn)
2.修改一个点x,该点的影响范围为其子树中所有点,因为子树的点到树根必经过x点。我dfs序上建立线段树,每个点维护当前点到根节点的答案,修改某个点的权值时,只需要对以当前点为根的子树进行修改即可。
查询时单点查询,时间复杂度为O(n * logn)

树链剖分好久没用了,比赛时敲模板一直在报错。。。
第二个方法还是挺直接的,dfs先构造父子关系以及深度,然后线段树维护即可

代码:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#define int long long
using namespace std;

unsigned long long val[1000009];
unsigned long long reval[1000009];
int in[1000009];
int out[1000009];
int inout[2000009];
vector<int>maps[1000009];
int cnt=1;
unsigned long long tree[8000009];

void dfs(int now,int pre,unsigned long long cc)//dfs序,顺便记录每个节点的价值和 
{
    inout[cnt]=now;
    in[now]=cnt;
    cnt++;
    reval[now] = cc+val[now]*val[now];
    for(int i=0;i<maps[now].size();i++)
    {
        if(maps[now][i]==pre) continue;
        dfs(maps[now][i],now,reval[now]);
    }
    inout[cnt]=now;
    out[now]=cnt;
    cnt++;
}

void build(int l,int r,int now)
{
    //tree[now] = 0;
    if(l==r)
    {
        tree[now]=reval[inout[l]];
        return;
    }


    build(l,(l+r)/2,now*2);
    build((l+r)/2+1,r,now*2+1);
}

int check(int l,int r,int now,int aim)
{
    if(l==r)
    {
        return tree[now];
    }

    if(tree[now]>0)
    {
        tree[now*2]+=tree[now];
        tree[now*2+1]+=tree[now];
        tree[now]=0;
    }

    if(aim<=(l+r)/2)
    check(l,(l+r)/2,now*2,aim);
    else
    check((l+r)/2+1,r,now*2+1,aim);
}

void change(int l,int r,int now,int ll,int rr,unsigned long long num)
{
    if(ll<=l&&r<=rr)
    {
        tree[now]+=num;
        return ;
    }

    if(tree[now]>0)
    {
        tree[now*2]+=tree[now];
        tree[now*2+1]+=tree[now];
        tree[now]=0;
    }

    if(rr<=(l+r)/2)
    change(l,(l+r)/2,now*2,ll,rr,num);
    else if(ll>=(l+r)/2+1)
    change((l+r)/2+1,r,now*2+1,ll,rr,num);
    else
    {
        change(l,(l+r)/2,now*2,ll,(l+r)/2,num);
        change((l+r)/2+1,r,now*2+1,(l+r)/2+1,rr,num);
    }
}

signed main(){

    int n,m,r,i,j,k,l;

    scanf("%lld",&n);
    scanf("%lld",&m);
    scanf("%lld",&r);

    for(i=1;i<=n;i++)
    {
        scanf("%lld",&j);

        val[i] = (unsigned long long)(j);
    }

    for(i=2;i<=n;i++)
    {
        scanf("%lld",&j);
        scanf("%lld",&k);
        maps[j].push_back(k);
        maps[k].push_back(j);
    }

    dfs(r,-1,0);

    build(1,2*n,1);

    unsigned long long aaa;
    while(m--)
    {
        scanf("%lld",&j);

        if(j==1)
        {
            scanf("%lld",&k);
            scanf("%lld",&l);

            aaa=val[k]+(unsigned long long)l;
            aaa=aaa*aaa-val[k]*val[k];
            val[k] = val[k]+(unsigned long long)l;
            change(1,2*n,1,in[k],out[k],aaa);
        }
        else
        {
            scanf("%lld",&k);
            l=check(1,2*n,1,out[k]);
            printf("%lld\n",l);
        }

    }

    return 0;
}