题目大意:给出一棵树,每个结点初始均为0,要求支持以下操作:路径加等差数列,询问路径上结点权值和,回到之前的某个版本,强制在线。
调到吐血。
很明显可以看出需要树链剖分+主席树来解决,由于需要在主席树上区间修改所以标记永久化。
区间维护等差数列需要在每个结点上维护 首项 和 公差。
树链剖分时在路径上加等差数列需要讨论,细节比较多,详见代码。
(我看错题了..注意回到某个版本并不舍弃在这之间的版本)
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 150005
#define int long long
using namespace std;
typedef long long LL;
int time_clock,tot_time;
namespace Segment_Tree {
struct Node {
Node* ch[2];
int sum,a0,d,l,r,ver;
Node(Node* tmp=NULL) {
if(tmp) {
ch[0]=tmp->ch[0];
ch[1]=tmp->ch[1];
sum=tmp->sum;
a0=tmp->a0;
d=tmp->d;
l=tmp->l;
r=tmp->r;
ver=tmp->ver;
}
else {
ch[0]=ch[1]=NULL;
sum=l=r=a0=d=ver=0;
}
}
void* operator new(size_t) {
static Node *C,*mempool;
if(C==mempool) mempool=(C=new Node[1<<20])+(1<<20);
return C++;
}
}*root[N];
void init(Node*& o,int l,int r) {
o=new Node();
o->l=l, o->r=r;
if(l==r) return ;
int mid=l+r>>1;
init(o->ch[0],l,mid), init(o->ch[1],mid+1,r);
return ;
}
int query(Node* o,int l,int r) {
int tmp=(2*o->a0+o->d*(l+r-2*o->l))*(r-l+1)/2;
if(o->l==l && o->r==r) return o->sum+tmp;
int mid=o->l+o->r>>1;
if(r<=mid) return tmp+query(o->ch[0],l,r);
if(l>mid) return tmp+query(o->ch[1],l,r);
return tmp+query(o->ch[0],l,mid)+query(o->ch[1],mid+1,r);
}
void change(Node*& o,int l,int r,int a0,int d) {
if(o->ver!=time_clock) {
Node* tmp=o;
o=new Node(tmp);
o->ver=time_clock;
}
if(o->l==l && o->r==r) {
o->a0+=a0;
o->d+=d;
return ;
}
o->sum+=(2*a0+d*(r-l))*(r-l+1)/2;
int mid=o->l+o->r>>1;
if(r<=mid) change(o->ch[0],l,r,a0,d);
else if(l>mid) change(o->ch[1],l,r,a0,d);
else change(o->ch[0],l,mid,a0,d), change(o->ch[1],mid+1,r,a0+d*(mid+1-l),d);
return ;
}
}
namespace Tree_Partition {
struct Edge {
int from,to,nxt;
Edge() {}
Edge(int _from,int _to,int _nxt):from(_from),to(_to),nxt(_nxt) {}
}e[N*2];
int fir[N],tot=-1;
void Add_Edge(int x,int y) {
e[++tot]=Edge(x,y,fir[x]), fir[x]=tot;
e[++tot]=Edge(y,x,fir[y]), fir[y]=tot;
return ;
}
int dfs_clock,pa[N],top[N],dpt[N],siz[N],son[N],pos[N],seq[N];
void dfs1(int x) {
siz[x]=1;
dpt[x]=dpt[pa[x]]+1;
for(int i=fir[x];~i;i=e[i].nxt) {
if(e[i].to==pa[x]) continue;
pa[e[i].to]=x;
dfs1(e[i].to);
siz[x]+=siz[e[i].to];
if(siz[son[x]]<siz[e[i].to]) son[x]=e[i].to;
}
return ;
}
void dfs2(int x) {
pos[x]=++dfs_clock;
seq[dfs_clock]=x;
if(son[pa[x]]==x) top[x]=top[pa[x]];
else top[x]=x;
if(son[x]) dfs2(son[x]);
for(int i=fir[x];~i;i=e[i].nxt) {
if(e[i].to==pa[x] || e[i].to==son[x]) continue;
dfs2(e[i].to);
}
return ;
}
int LCA(int x,int y) {
while(top[x]!=top[y]) {
if(dpt[top[x]]<dpt[top[y]]) swap(x,y);
x=pa[top[x]];
}
if(dpt[x]<dpt[y]) swap(x,y);
return y;
}
int query(int x,int y) {
using Segment_Tree :: query;
using Segment_Tree :: root;
int ans=0;
while(top[x]!=top[y]) {
if(dpt[top[x]]<dpt[top[y]]) swap(x,y);
ans+=query(root[time_clock],pos[top[x]],pos[x]);
x=pa[top[x]];
}
if(dpt[x]<dpt[y]) swap(x,y);
ans+=query(root[time_clock],pos[y],pos[x]);
return ans;
}
void change(int x,int y,int a0,int d) {
using Segment_Tree :: root;
using Segment_Tree :: change;
tot_time++;
root[tot_time]=root[time_clock];
time_clock=tot_time;
int lca=LCA(x,y);
int an=a0+d*(dpt[x]+dpt[y]-2*dpt[lca]);
while(top[x]!=top[y]) {
if(dpt[top[x]]>dpt[top[y]]) {
change(root[time_clock],pos[top[x]],pos[x],a0+d*(dpt[x]-dpt[top[x]]),-d);
a0+=(dpt[x]-dpt[top[x]]+1)*d;
x=pa[top[x]];
}
else {
change(root[time_clock],pos[top[y]],pos[y],an-d*(dpt[y]-dpt[top[y]]),d);
an-=(dpt[y]-dpt[top[y]]+1)*d;
y=pa[top[y]];
}
}
if(dpt[x]>dpt[y]) change(root[time_clock],pos[y],pos[x],an,-d);
else change(root[time_clock],pos[x],pos[y],a0,d);
return ;
}
}
#undef int
int main() {
#define int long long
int n,m;
scanf("%lld%lld",&n,&m);
using namespace Tree_Partition;
memset(fir,-1,sizeof fir);
for(int i=1;i<n;i++) {
int x,y;
scanf("%lld%lld",&x,&y);
Add_Edge(x,y);
}
dfs1(1), dfs2(1);
Segment_Tree :: init(Segment_Tree :: root[0],1,n);
int last_ans=0;
while(m--) {
char mode[5];
int x,y,a0,d;
scanf("%s",mode);
if(mode[0]=='c') {
scanf("%lld%lld%lld%lld",&x,&y,&a0,&d);
x^=last_ans, y^=last_ans;
change(x,y,a0,d);
}
else if(mode[0]=='q') {
scanf("%lld%lld",&x,&y);
x^=last_ans, y^=last_ans;
printf("%lld\n",last_ans=query(x,y));
}
else {
scanf("%lld",&x);
x^=last_ans;
time_clock=x;
}
}
return 0;
}