抽象题意:求可持久化树链剖分
一道巨型码农题!
对于每个数,我们要求 aj∗i∗(i+1)/2 ,
拆一下: aj∗(i+q)∗(i+1+q)/2 ,瞬间可搞,
然后维护一大堆东西即可,
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
using namespace std;
typedef long long LL;
const int N=100500,maxlongint=2147483640;
const LL mo=20160501,ny=10080251;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int n,m,ANS;
int B[N*2][2],A[N],B0;
int root[N],now,NOW;
struct qqw{int c,s,fa,g,a,ld;int G[20];}a[N];
int zx[N],b0,ansl;
struct qqww
{int l,r,root;LL sl,sr,pl,pr,s,la;}b[N*78],ans;
void join(int q,int w)
{
B[++B0][0]=A[q],A[q]=B0,B[B0][1]=w;
B[++B0][0]=A[w],A[w]=B0,B[B0][1]=q;
}
int dfs1(int q,int e,int fa)
{
a[q].fa=a[q].G[0]=fa;a[q].c=e;a[q].s=1;
efo(i,q)if(B[i][1]!=fa)a[q].s+=dfs1(B[i][1],e+1,q);
return a[q].s;
}
int dfs2(int q,int e,int fa)
{
if(!e)e=q;
a[q].g=++zx[0];zx[zx[0]]=q;a[q].ld=e;
int mx=0;
efo(i,q)if(B[i][1]!=fa && a[mx].s<a[B[i][1]].s)mx=B[i][1];
if(mx)dfs2(mx,e,q);
efo(i,q)if(B[i][1]!=fa && B[i][1]!=mx)dfs2(B[i][1],0,q);
}
void merge(qqww &ans,qqww a,qqww b,int a1,int b1)
{
(ans.s=a.s+b.s)%=mo;
(ans.sl=a.sl+b.sl+b.s*a1)%=mo;
(ans.sr=a.sr+b1*a.s+b.sr)%=mo;
(ans.pl=a.pl+b.pl+2*b.sl*a1+a1*a1*b.s)%=mo;
(ans.pr=a.pr+2*a.sr*b1+b1*b1*a.s+b.pr)%=mo;
}
void build(int l,int r,int &e)
{
e=++b0;
if(l==r){b[e].pl=b[e].pr=b[e].sl=b[e].sr=0,b[e].s=a[zx[l]].a;return;}
int t=(l+r)/2;
build(l,t,b[e].l);build(t+1,r,b[e].r);
merge(b[e],b[b[e].l],b[b[e].r],t-l+1,r-t);
}
int upa(int q,int e)
{
while(a[q].c>e)
{
int i=0;
while(a[a[q].G[i+1]].c>=e)i++;
q=a[q].G[i];
}
return q;
}
int upb(int q,int w)
{
while(q!=w)
{
int i=0;
while(a[q].G[i+1]!=a[w].G[i+1])i++;
q=a[q].G[i];w=a[w].G[i];
}
return q;
}
int fdds(int q,int w)
{
int q1=upa(q,a[w].c),w1=upa(w,a[q].c);
q1=upb(q1,w1);
return a[q].c+a[w].c-2*a[q1].c+1;
}
void doit(qqww &q,int lo)
{
if(!q.la)return;lo--;
if(!lo)
{
q.s+=q.la;q.la=0;
return;
}
b[++b0]=b[q.l],q.l=b0,(b[b0].la+=q.la)%=mo;
b[++b0]=b[q.r],q.r=b0,(b[b0].la+=q.la)%=mo;
LL w=lo*(lo+1)/2;
if(w%3)(w*=(2*lo+1)/3)%=mo;else (w=w/3*(2*lo+1))%=mo;
(w*=q.la)%=mo;
(q.pl+=w)%=mo;(q.pr+=w)%=mo;
w=(lo*(lo+1)/2)%mo*q.la%mo;
(q.sl+=w)%=mo;(q.sr+=w)%=mo;
(q.s+=(lo+1)*q.la)%=mo;
q.la=0;
}
void find(int l,int r,int e,int l1,int r1)
{
doit(b[e],r-l+1);
if(l==l1 && r==r1)
{
qqww ans1=ans;
merge(ans1,ans,b[e],l-ansl,r-l+1);
ans=ans1;
return;
}
int t=(l+r)/2;
if(r1<=t)find(l,t,b[e].l,l1,r1),doit(b[b[e].r],r-t);
else if(t<l1)doit(b[b[e].l],t-l+1),find(t+1,r,b[e].r,l1,r1);
else find(l,t,b[e].l,l1,t),find(t+1,r,b[e].r,t+1,r1);
merge(b[e],b[b[e].l],b[b[e].r],t-l+1,r-t);
}
LL ss(LL p,LL s,LL su,LL ad){return(p+2*s*ad+ad*ad*su+s+ad*su)%mo;}
LL solue(int q,int w)
{
LL ANS=0,l=fdds(q,w)-1,r=0;
int q1,w1;
while((q1=a[q].ld)!=(w1=a[w].ld))
{
ans.s=ans.sl=ans.sr=ans.pl=ans.pr=0;
if(a[q1].c>a[w1].c)
{
ansl=a[q1].g,find(1,n,root[now],a[q1].g,a[q].g);
l-=a[q].c-a[q1].c+1;
(ANS+=ss(ans.pl,ans.sl,ans.s,l+1))%=mo;
q=a[q1].fa;
}else
{
ansl=a[w1].g,find(1,n,root[now],a[w1].g,a[w].g);
(ANS+=ss(ans.pr,ans.sr,ans.s,r))%=mo;
r+=a[w].c-a[w1].c+1;
w=a[w1].fa;
}
}
ans.s=ans.sl=ans.sr=ans.pl=ans.pr=0;
if(a[q].c>a[w].c)
{
ansl=a[w].g,find(1,n,root[now],a[w].g,a[q].g);
l-=a[q].c-a[w].c+1;
(ANS+=ss(ans.pl,ans.sl,ans.s,l+1))%=mo;
}else
{
ansl=a[q].g,find(1,n,root[now],a[q].g,a[w].g);
(ANS+=ss(ans.pr,ans.sr,ans.s,r))%=mo;
r+=a[w].c-a[q].c+1;
}
return (ANS*ny)%mo;
}
void change(int l,int r,int e1,int &e2,int nw,int l1,int r1,int l2)
{
doit(b[e1],r-l+1);
if(b[e2].root!=nw)b[e2=++b0]=b[e1],b[e2].root=nw;else doit(b[e2],r-l+1);
if(l==l1&&r==r1){b[e2].la+=l2;doit(b[e2],r-l+1);return;}
int t=(l+r)/2;
if(r1<=t)change(l,t,b[e1].l,b[e2].l,nw,l1,r1,l2),doit(b[b[e2].r],r-t);
else if(t<l1)doit(b[b[e2].l],t-l+1),change(t+1,r,b[e1].r,b[e2].r,nw,l1,r1,l2);
else change(l,t,b[e1].l,b[e2].l,nw,l1,t,l2),change(t+1,r,b[e1].r,b[e2].r,nw,t+1,r1,l2);
merge(b[e2],b[b[e2].l],b[b[e2].r],t-l+1,r-t);
}
void modify(int q,int w,int e)
{
int q1,w1;
while((q1=a[q].ld)!=(w1=a[w].ld))
{
if(a[q1].c<a[w1].c)swap(q,w),swap(q1,w1);
change(1,n,root[now],root[NOW+1],NOW+1,a[q1].g,a[q].g,e);
q=a[q1].fa;
}
if(a[q].c<a[w].c)swap(q,w);
change(1,n,root[now],root[NOW+1],NOW+1,a[w].g,a[q].g,e);
now=++NOW;
}
int main()
{
freopen("zootopia.in","r",stdin);
freopen("zootopia.out","w",stdout);
int q,w,e,_;
read(n),read(_);
fo(i,1,n-1)read(q),read(w),join(q,w);
fo(i,1,n)read(a[i].a);
dfs1(1,1,0);
fo(j,1,18)fo(i,1,n)a[i].G[j]=a[a[i].G[j-1]].G[j-1];
dfs2(1,0,0);
now=NOW=0;
build(1,n,root[0]);
LL last=0;
while(_--)
{
read(e),read(q);q=q^last;
if(e==1)read(w),read(e),w^=last,modify(q,w,e);
else if(e==2)read(w),w^=last,last=solue(q,w),printf("%lld\n",last);
else now=q;
}
return 0;
}