题目描述
传送门
题目大意:给出一个n个节点的树
操作1:x,y a,k 将x到y路径上的点加入一个首项为a,公差为k等差数列
操作2:x,y 查询路径上的点权和
操作3:x回到第x次操作1后的结果
题解
区间修改区间查询,对于每个区间维护当前区间的首项和公差,以及区间的权值和。
标记永久化,查询的时候将路径上的首项公差加和,最后计入答案即可。
注意区间首项的计算,区间修改时对于右儿子首项应该是
a+max(0,mid+1−max(l,ll))∗k
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 200003
#define LL long long
using namespace std;
struct data{
int ls,rs;
LL a,k,sum;
}tr[N*100];
int n,m,root[N],mp[N],now,sz,cnt,pos[N],fa[N],L[N],R[N],top,top1,L1[N],R1[N],T[N];
int tot,nxt[N],point[N],v[N],belong[N],deep[N],size[N],son[N],last;
void add(int x,int y)
{
tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void dfs(int x,int f)
{
deep[x]=deep[f]+1; size[x]=1;
for (int i=point[x];i;i=nxt[i]){
if (v[i]==f) continue;
fa[v[i]]=x;
dfs(v[i],x);
size[x]+=size[v[i]];
if (size[v[i]]>size[son[x]]) son[x]=v[i];
}
}
void dfs1(int x,int chain)
{
belong[x]=chain; pos[x]=++sz;
if (!son[x]) return;
dfs1(son[x],chain);
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa[x]&&v[i]!=son[x])
dfs1(v[i],v[i]);
}
LL query(int i,int l,int r,int ll,int rr,LL a,LL k)
{
if (ll<=l&&r<=rr) {
LL len=r-l+1;
LL an=(len-1)*k+a;
return tr[i].sum+(a+an)*len/2;
}
int mid=(l+r)/2;
LL ans=0;
if (ll<=mid) ans+=query(tr[i].ls,l,mid,ll,rr,a+tr[i].a,k+tr[i].k);
if (rr>mid) ans+=query(tr[i].rs,mid+1,r,ll,rr,a+tr[i].a+(LL)max(0,mid+1-l)*(k+tr[i].k),k+tr[i].k);
return ans;
}
void update(int now,int l,int r)
{
int ls=tr[now].ls; int rs=tr[now].rs;
LL len=r-l+1; LL an=tr[now].a+(len-1)*tr[now].k;
tr[now].sum=(tr[now].a+an)*len/2;
if (ls) tr[now].sum+=tr[ls].sum;
if (rs) tr[now].sum+=tr[rs].sum;
}
void insert(int &i,int j,int l,int r,int ll,int rr,LL a,LL v,int t)
{
if (i<=t) i=++sz,tr[i]=tr[j];
if (ll<=l&&r<=rr) {
tr[i].a+=a;
tr[i].k+=v;
update(i,l,r);
return;
}
int mid=(l+r)/2;
if (ll<=mid) insert(tr[i].ls,tr[j].ls,l,mid,ll,rr,a,v,t);
if (rr>mid) insert(tr[i].rs,tr[j].rs,mid+1,r,ll,rr,a+(LL)max(0,mid+1-max(l,ll))*v,v,t);
update(i,l,r);
}
void solve(int x,int y,LL a,LL k)
{
top=0,top1=0;
while (belong[x]!=belong[y]) {
if (deep[belong[x]]>=deep[belong[y]]) {
++top; L[top]=pos[belong[x]]; R[top]=pos[x];
x=fa[belong[x]];
}
else {
++top1; L1[top1]=pos[belong[y]]; R1[top1]=pos[y];
y=fa[belong[y]];
}
}
if (deep[x]>deep[y]) {
++top; L[top]=pos[y]; R[top]=pos[x];
}
else {
++top1; L1[top1]=pos[x]; R1[top1]=pos[y];
}
LL head=0;
for (int i=1;i<=top;i++) {
LL len=R[i]-L[i]+1;
head+=len; LL a1=(head-1)*k+a;
insert(root[now],root[last],1,n,L[i],R[i],a1,-k,T[now]);
}
head++;
for (int i=top1;i>=1;i--) {
LL a1=(head-1)*k+a;
insert(root[now],root[last],1,n,L1[i],R1[i],a1,k,T[now]);
LL len=R1[i]-L1[i]+1;
head+=len;
}
}
LL calc(int x,int y)
{
LL ans=0;
while (belong[x]!=belong[y]) {
if (deep[belong[x]]<deep[belong[y]]) swap(x,y);
ans+=query(root[now],1,n,pos[belong[x]],pos[x],0,0);
x=fa[belong[x]];
}
if (deep[x]>deep[y]) swap(x,y);
ans+=query(root[now],1,n,pos[x],pos[y],0,0);
return ans;
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<n;i++){
int x,y; scanf("%d%d",&x,&y);
add(x,y);
}
dfs(1,0); dfs1(1,1);
LL ans=0; sz=0;
for (int i=1;i<=m;i++) {
char s[3];
scanf("%s",s);
if (s[0]=='c') {
LL x,y; LL a,k;
scanf("%lld%lld%lld%lld",&x,&y,&a,&k);
x^=ans; y^=ans;
last=now;
now=++cnt; T[now]=sz;
solve((int)x,(int)y,a,k);
}
else if (s[0]=='q') {
LL x,y; scanf("%lld%lld",&x,&y);
x^=ans; y^=ans;
printf("%lld\n",ans=calc((int)x,(int)y));
}
else {
LL x; scanf("%lld",&x); x^=ans;
now=x;
}
}
}