给出一个N个节点的数,和M次操作。每次操作的类型如下:
1,x,y,z,将x到y的路径上的ai加上z
2,x,y,询问x到y的路径上,ai*(1+2+..+n-i)的和
3,x,将所有的a变更回第x次修改之后的状态。
强制在线。
N,M<=10^5.
裸题——码农一道!
可持久化线段树+树链剖分兹磁树上的区间查询&修改。
代码量飞飞飞飞起~
至于区间合并请自行脑补。
#include<cstdio>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,b,a) for(int i=b;i>=a;i--)
#define efo(i,v) for(int i=last[v];i;i=next[i])
using namespace std;
typedef long long ll;
const int N=100010,M=N*2,mo=20160501,ny=10080251;
int n,m,num,tot,now,to[M],next[M],last[N],root[N];
int son[N],fa[N],top[N],size[N],w[N],re[N],f[N][18];
ll c[N],dep[N];
struct node
{
int l,r;
ll lz,ad2,ad,ai,d,d2;
}a[N*60];
void link(int u,int v)
{
to[++tot]=v,next[tot]=last[u],last[u]=tot;
}
void dfs1(int v,int from,int d)
{
size[v]=1,dep[v]=d;
int k=0;
efo(i,v)
{
int u=to[i];
if(u==from) continue;
dfs1(u,v,d+1);
size[v]+=size[u],fa[u]=f[u][0]=v;
if(size[u]>size[k]) k=u;
}
son[v]=k;
}
void dfs2(int v,int from,int p)
{
top[v]=p,w[v]=++num,re[num]=v;
if(!son[v]) return;
dfs2(son[v],v,p);
efo(i,v)
{
int u=to[i];
if(u==from || u==son[v]) continue;
dfs2(u,v,u);
}
}
int getlca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
fd(i,int(log2(dep[u])),0)
if(dep[f[u][i]]>=dep[v]) u=f[u][i];
fd(i,int(log2(dep[u])),0)
if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
if(u!=v) return f[u][0];
return u;
}
void up(int v)
{
a[v].ai=(a[a[v].l].ai+a[a[v].r].ai)%mo;
a[v].ad=(a[a[v].l].ad+a[a[v].r].ad)%mo;
a[v].ad2=(a[a[v].l].ad2+a[a[v].r].ad2)%mo;
}
void down(int v,int l,int r)
{
if(!a[v].lz) return;
ll k=a[v].lz;
int mid=(l+r)>>1;
a[++m]=a[a[v].l],(a[m].ai+=k*(mid-l+1))%=mo,(a[m].ad+=k*a[m].d)%=mo,(a[m].ad2+=k*a[m].d2)%=mo,a[m].lz+=k;
a[v].l=m;
a[++m]=a[a[v].r],(a[m].ai+=k*(r-mid))%=mo,(a[m].ad+=k*a[m].d)%=mo,(a[m].ad2+=k*a[m].d2)%=mo,a[m].lz+=k;
a[v].r=m;
a[v].lz=0;
}
void build(int &v,int l,int r)
{
v=++m;
if(l==r)
{
a[v].ai=c[re[l]],a[v].ad=c[re[l]]*dep[re[l]]%mo,a[v].ad2=c[re[l]]*dep[re[l]]*dep[re[l]]%mo;
a[v].d=dep[re[l]];a[v].d2=a[v].d*dep[re[l]]%mo;
return;
}
int mid=(l+r)>>1;
build(a[v].l,l,mid);
build(a[v].r,mid+1,r);
up(v);
a[v].d=a[a[v].l].d+a[a[v].r].d;
a[v].d2=a[a[v].l].d2+a[a[v].r].d2;
}
ll query(int v,int l,int r,int x,int y,ll t)
{
if(l==x && r==y) return ((a[v].ad2+a[v].ad*(2*t+1)%mo+a[v].ai*t*(t+1)%mo)%mo+mo)%mo;
down(v,l,r);
int mid=(l+r)>>1;
if(x>mid) return query(a[v].r,mid+1,r,x,y,t);
else
if(y<=mid) return query(a[v].l,l,mid,x,y,t);
else return (query(a[v].l,l,mid,x,mid,t)+query(a[v].r,mid+1,r,mid+1,y,t))%mo;
}
ll solve(int x,int y,int k)
{
ll ans=0;
int len=0,p,u=x,v=y,lca=getlca(x,y);
while(top[u]!=top[v])
{
if(dep[top[u]]>dep[top[v]])
{
p=top[u];
(ans+=query(root[k],1,n,w[p],w[u],dep[y]-2*dep[lca]))%=mo;
u=fa[p];
}
else
{
p=top[v];
(ans+=query(root[k],1,n,w[p],w[v],-dep[y]-1))%=mo;
v=fa[p];
}
}
if(dep[u]>=dep[v]) (ans+=query(root[k],1,n,w[v],w[u],dep[y]-2*dep[lca]))%=mo;
else (ans+=query(root[k],1,n,w[u],w[v],-dep[y]-1))%=mo;
return ans;
}
void modify(int u,int &v,int l,int r,int x,int y,ll z)
{
down(u,l,r);
if(u==v) a[v=++m]=a[u];
if(l==x && r==y)
{
(a[v].ai+=z*(r-l+1))%=mo,a[v].lz+=z;
(a[v].ad+=z*a[v].d)%=mo;
(a[v].ad2+=z*a[v].d2)%=mo;
return;
}
int mid=(l+r)>>1;
if(x>mid) modify(a[u].r,a[v].r,mid+1,r,x,y,z);
else
if(y<=mid) modify(a[u].l,a[v].l,l,mid,x,y,z);
else
modify(a[u].l,a[v].l,l,mid,x,mid,z),modify(a[u].r,a[v].r,mid+1,r,mid+1,y,z);
up(v);
}
void change(int u,int v,int k,ll z)
{
if(!root[k]) root[k]=root[now];
int x;
while(top[u]!=top[v])
{
if(dep[top[u]]>dep[top[v]]) swap(u,v);
x=top[v];
modify(root[now],root[k],1,n,w[x],w[v],z);
v=fa[x];
}
if(dep[u]>dep[v]) swap(u,v);
modify(root[now],root[k],1,n,w[u],w[v],z);
}
int main()
{
freopen("zootopia.in","r",stdin);
freopen("zootopia.out","w",stdout);
int _,tp,x,y,z,k=0;
ll ans=0;
scanf("%d %d",&n,&_);
fo(i,1,n-1)
{
scanf("%d %d",&x,&y);
link(x,y),link(y,x);
}
fo(i,1,n) scanf("%lld",&c[i]);
dfs1(1,0,1);
dfs2(1,0,1);
fo(j,1,int(log2(n)))
fo(i,1,n) f[i][j]=f[f[i][j-1]][j-1];
build(root[0],1,n);
while(_--)
{
scanf("%d %d",&tp,&x);
x^=ans;
if(tp==1)
{
scanf("%d %d",&y,&z);
y^=ans;
change(x,y,++k,z);
now=k;
}
else
if(tp==2)
{
scanf("%d",&y);
y^=ans;
ans=solve(x,y,now)*ny%mo;
printf("%lld\n",ans);
}
else now=x;
}
fclose(stdin);fclose(stdout);
return 0;
}