题目大意
给你一棵树,每个点有一个点权hih_ihi,修改操作:把距离xxx小于等于ddd的点的点权乘上www,对LLL取模,LLL在修改和查询前给出,查询某一个点的点权
题解
一开始看错题了,没发现d≤40d\le 40d≤40,由于ddd很小,考虑有关ddd的做法,我们不妨把修改全部用一种标记来表示,设tagx,ytag_{x,y}tagx,y表示在xxx子树中距离yyy的点的点权需要乘上tagx,ytag_{x,y}tagx,y,只用这种标记能否不重不漏的覆盖所有修改的点呢,答案是可行的,比如说有一个修改x,d,wx,d,wx,d,w,可以把xxx的ddd级祖先都找出来,记为fafafa,对于它们都这样打上标记tagfa,d−dis(fa,x)∗=w,tagfa,d−dis(fa,x)−1∗=wtag_{fa,d-dis(fa,x)}*=w,tag_{fa,d-dis(fa,x)-1}*=wtagfa,d−dis(fa,x)∗=w,tagfa,d−dis(fa,x)−1∗=w,不难发现这样就能覆盖所有需要修改的点,并且不会修改多次
code
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
#define gc() (fp==fq&&(fq=(fp=fr)+fread(fr,1,1<<20,stdin))==fp?EOF:*fp++)
char fr[1<<21],*fp,*fq;
void read(int &res)
{
res=0;char ch=gc();
while(ch<'0'||ch>'9') ch=gc();
while('0'<=ch&&ch<='9') res=(res<<1)+(res<<3)+(ch^48),ch=gc();
}
void read(ll &res)
{
res=0;char ch=gc();
while(ch<'0'||ch>'9') ch=gc();
while('0'<=ch&&ch<='9') res=(res<<1)+(res<<3)+(ch^48),ch=gc();
}
void write(ll res)
{
if(res>=10) write(res/10),putchar('0'+res%10);
else putchar('0'+res);
}
const int N=2e5+1000,B=40;
int n,q,fa[N+10],st[N+10],tot;ll l,h[N+10],tag[B+10][N+10];
struct edge
{
int to,last;
}e[N<<1|1];
void add(int a,int b)
{
e[++tot].to=b;
e[tot].last=st[a];
st[a]=tot;
}
void dfs(int u)
{
for(int i=st[u],v;i!=0;i=e[i].last)
{
v=e[i].to;
if(v==fa[u]) continue;
fa[v]=u,dfs(v);
}
}
void pushtag(int u,int d,ll k)
{
if(d<0) return;
if(d!=0) tag[d-1][u]*=k,tag[d-1][u]%=l;
tag[d][u]*=k,tag[d][u]%=l;
pushtag(fa[u],d-1,k);
}
ll querymul(int u,int d)
{
if(d>40) return 1;
return querymul(fa[u],d+1)*tag[d][u]%l;
}
int main()
{
read(n),read(l);
for(int i=1,a,b;i<n;i++) read(a),read(b),add(a,b),add(b,a);
dfs(1);
for(int i=1;i<=n;i++) read(h[i]);
for(int i=0;i<=n;i++) for(int j=0;j<=B;j++) tag[j][i]=1;
read(q);
for(int t,x,d,w;q--;)
{
read(t),read(x);
if(t==1) read(d),read(w),pushtag(x,d,w);
else write(h[x]*querymul(x,0)%l),putchar('\n');
}
return 0;
}