操作1:1,x,y,z把x到y的点权值加z。
操作2:2,x,y把x到y的点一次放进一个数组a里面,统计答案 ans=∑ni=1a[i]∗∑n−ij=1 。
操作3:3,x所有点的状态回到第x次修改后的。
不过知道是码农题,在比赛的最后30分钟,竟然毫不犹豫地对其宣战。
失败告终…………………………………………….TAT
明显的可持久化线段树,如果要回到历史版本,经典的以时间为一轴的可持久化线段树。
文绉绉的!其实平常统计颜色的时候,当一个节点颜色不同会动态多开一个点。
这道题,当一个点被改过就多开一个点。
线段树只用统计4个部分: 长度,和,值∗序号,值∗序号2
合并有些复杂,慢慢的细推,有利于锻炼思维。实在不懂就看程序。
因为序号的遍历方式可能是顺序也可能是逆序,所以每个区间要存两个遍历方式的值。
我打了个struct套struct,这样方便操作。
树链剖分就可以了。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
typedef long long ll;
const ll maxn=200007,mo=20160501,ni=10080251;
int i,j,k,l,n,m;
int first[maxn*2],next[maxn*2],last[maxn*2],a[maxn],num,tot,u,v;
int deep[maxn],f[maxn][21],size[maxn],son[maxn],top[maxn],w[maxn],fw[maxn],tmp,ceng;
int root[maxn],now;
ll ans;
ll chu3(ll x,ll y) {
if (x%3)return y/3%mo*x%mo;return x/3%mo*y%mo;
}
struct sx{
ll len,sqr,sum,ji;
void kong(){len=sqr=sum=ji=0;}
friend sx operator +(sx x,sx y){
sx z;
z.len=x.len+y.len;
z.sum=(x.sum+y.sum)%mo;
z.ji=(x.ji+y.ji+x.len*y.sum%mo)%mo;
z.sqr=(x.sqr+y.sqr+x.len*x.len%mo*y.sum%mo+2*y.ji%mo*x.len%mo)%mo;
return z;
}
void add(ll z){
sum=(sum+z*len%mo)%mo;
ji=(ji+len*(len+1)%mo*ni%mo*z%mo)%mo;
sqr=(chu3(2*len+1,len*(len+1)/2)*z%mo+sqr)%mo;
}
}ans1,ans2;
struct node{
sx up,down;
int l,r,biao,shu;
}t[maxn*25],op;
void add(int x,int y){
last[++num]=y;next[num]=first[x];first[x]=num;
}
void dfs1(int x,int y){
int i,k=0;
deep[x]=deep[y]+1;f[x][0]=y;size[x]=1;
rep(i,x){
if(last[i]!=y){
dfs1(last[i],x);
size[x]+=size[last[i]];
if(size[last[i]]>k)k=size[last[i]],son[x]=last[i];
}
}
}
void dfs2(int x,int y){
int i;
w[x]=++tot,fw[tot]=x,top[x]=y;
if(!son[x])return;
dfs2(son[x],y);
rep(i,x){
if(last[i]!=f[x][0]&&last[i]!=son[x])dfs2(last[i],last[i]);
}
}
int lca(int x,int y){
int i;if(deep[x]y])swap(x,y);
fod(i,20,0)if(deep[f[x][i]]>deep[y])x=f[x][i];
if(deep[x]>deep[y])x=f[x][0];
fod(i,20,0)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
if(x!=y)return f[x][0];return x;
}
node merge(node x,node y){
node z;
z.down=x.down+y.down;
z.up=y.up+x.up;
return z;
}
void build(int &x,int l,int r){
x=++tmp;
if(l==r){
t[x].up.len=t[x].down.len=1;
t[x].up.sum=t[x].down.sum=t[x].up.ji=t[x].down.ji=t[x].up.sqr=t[x].down.sqr=a[fw[l]];
return;
}
int mid=(l+r)/2;
build(t[x].l,l,mid);
build(t[x].r,mid+1,r);
t[x].down=t[t[x].l].down+t[t[x].r].down;
t[x].up=t[t[x].r].up+t[t[x].l].up;
}
void back(int &x,int y,ll z){
if(!x)return;
t[++tmp]=t[x];x=tmp;
t[x].shu=y;t[x].biao+=z;
t[x].up.add(z);t[x].down.add(z);
}
void down(int x){
if(t[x].biao){
back(t[x].l,t[x].shu,t[x].biao);
back(t[x].r,t[x].shu,t[x].biao);
t[x].biao=0;
}
}
void change(int &x,int l,int r,int y,int z,ll o){
if(!x)return;
down(x);
if(l==y&&r==z){back(x,ceng,o);return;}
int mid=(l+r)/2;
if(t[x].shu!=ceng){
t[++tmp]=t[x];x=tmp;
t[x].shu=ceng;
}
if(z<=mid)change(t[x].l,l,mid,y,z,o);
else if(y>mid)change(t[x].r,mid+1,r,y,z,o);
else change(t[x].l,l,mid,y,mid,o),change(t[x].r,mid+1,r,mid+1,z,o);
t[x].down=t[t[x].l].down+t[t[x].r].down;
t[x].up=t[t[x].r].up+t[t[x].l].up;
}
void gai(int x,int y,ll z){
int f1=top[x],f2=top[y];root[++ceng]=root[now];
while(f1!=f2){
if(deep[f1]x,y),swap(f1,f2);
change(root[ceng],1,n,w[f1],w[x],z);
x=f[f1][0],f1=top[x];
}
if(deep[x]y])swap(x,y);
change(root[ceng],1,n,w[y],w[x],z);
now=ceng;
}
int chang(int x,int y){
int o=lca(x,y);
return deep[x]+deep[y]-2*deep[o]+1;
}
node find(int x,int l,int r,int y,int z){
if(!x)return op;
down(x);
if(l==y&&r==z)return t[x];
int mid=(l+r)/2;
if(z<=mid)return find(t[x].l,l,mid,y,z);
else if(y>mid)return find(t[x].r,mid+1,r,y,z);
else return merge(find(t[x].l,l,mid,y,mid),find(t[x].r,mid+1,r,mid+1,z));
}
void zhao(int x,int y){
ans1.kong(),ans2.kong();
int o=lca(x,y),ff=top[x];
while(deep[ff]>deep[o]){
ans1=ans1+find(root[now],1,n,w[ff],w[x]).up;
x=f[ff][0],ff=top[x];
}
ff=top[y];
while(deep[ff]>deep[o]){
ans2=find(root[now],1,n,w[ff],w[y]).down+ans2;
y=f[ff][0],ff=top[y];
}
if(deep[x]y])ans1=ans1+find(root[now],1,n,w[x],w[y]).down;
else ans2=find(root[now],1,n,w[y],w[x]).up+ans2;
ans1=ans1+ans2;
}
int main(){
freopen("zootopia.in","r",stdin);
freopen("zootopia.out","w",stdout);
// freopen("fan.in","r",stdin);
// freopen("fan.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,n-1){
scanf("%d%d",&k,&l);
add(k,l);
add(l,k);
}
dfs1(1,0);
dfs2(1,1);
fo(j,1,20){
fo(i,1,n){
f[i][j]=f[f[i][j-1]][j-1];
}
}
fo(i,1,n)scanf("%d",&a[i]);
build(root[0],1,n);
for(;m;m--){
scanf("%d%d",&k,&u);u^=ans;
if(k==1){
scanf("%d%d",&v,&l);v^=ans;
gai(u,v,l);
}
else if(k==2){
scanf("%d",&v);v^=ans;
ll q=chang(u,v);
zhao(u,v);
// ans=ni;
// ans=ans*((-(2*q+1)*ans1.ji%mo+(q+1)*q%mo*ans1.sum%mo+ans1.sqr)%mo+mo)%mo;
ans=(q*(q+1)%mo*ans1.sum%mo-(2*q+1)*ans1.ji%mo+ans1.sqr+mo)%mo;
ans=(ans*ni)%mo;
printf("%lld\n",ans);
}
else{
now=u;
}
}
}