题解
此题的一种经典做法:套两颗LCT,一颗维护权值,一颗维护形态。
形态树里的每一个节点都有一个对应的权值树里的点。
对于值的区间翻转,只翻转权值树。其他操作则两棵树一起操作。
在形态树中操作时,对于节点之间关系的修改,对应权值中的点可以通过bst找k大完成。
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<cstdlib>
using namespace std;
typedef long long ll;
const int N=5e4+10;
const ll inf=1LL<<60;
int n,m,R;
char s[12];
inline int rd()
{
char ch=getchar();int x=0,f=1;
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
return x*f;
}
struct Ta{
struct Node{
Node *ch[2],*f;int sz,rv;
ll ad,v,mn,mx,sum;
void reverse(){
rv^=1;swap(ch[0],ch[1]);
}
void update(){
sz=ch[0]->sz+1+ch[1]->sz;
sum=ch[0]->sum+v+ch[1]->sum;
mn=min(min(ch[0]->mn,ch[1]->mn),v);
mx=max(max(ch[0]->mx,ch[1]->mx),v);
}
void change(int w){
ad+=w;v+=w;mn+=w;mx+=w;sum+=1ll*sz*w;
}
void pushdown(Node *null){
if(rv){
if(ch[0]!=null) ch[0]->reverse();
if(ch[1]!=null) ch[1]->reverse();
rv=0;
}
if(ad){
if(ch[0]!=null) ch[0]->change(ad);
if(ch[1]!=null) ch[1]->change(ad);
ad=0;
}
}
}*null,t[N];
Ta(){null=t;null->f=null->ch[0]=null->ch[1]=null;null->ad=null->sz=null->sum=0;null->mn=inf;null->mx=-inf;}
void rotate(Node *x){
if(x==null || x->f==null) return;Node *y=x->f;Node *z=y->f;
int s= y->ch[1]==x,gs= z->ch[1]==y;x->f=z;
if(z!=null) z->ch[gs]=x;
y->ch[s]=x->ch[s^1];x->ch[s^1]->f=y;x->ch[s^1]=y;y->f=x;y->update();x->update();
}
Node *sta[N];
void splay(Node *x){
Node *y=x;int top=0;
while(y!=null) {sta[++top]=y;y=y->f;}
for(int i=top;i;i--) sta[i]->pushdown(null);
while(x->f!=null){
if(x->f->f==null) rotate(x);
else {
(x->f->f->ch[1]==x->f)^(x->f->ch[1]==x) ?rotate(x):rotate(x->f);rotate(x);
}
}
}
Node* kth(Node *x,int k){
if(x->sz<k) return null;
Node *y=x;
while(k){
y->pushdown(null);
if(y->ch[0]->sz+1==k) break;
y->ch[0]->sz>=k? y=y->ch[0]:(k-=(y->ch[0]->sz+1),y=y->ch[1]);
}
splay(y);return y;
}
}Val;
struct Tb{
struct Node{
Node *ch[2],*p,*f;Ta:: Node *val;
int rv,sz;
void reverse(){
rv^=1;swap(ch[0],ch[1]);
}
void update(){
sz=ch[0]->sz+1+ch[1]->sz;
}
void pushdown(Node *null){
if(rv){
if(ch[0]!=null) ch[0]->reverse();
if(ch[1]!=null) ch[1]->reverse();
rv=0;
}
}
}*null,t[N];
Tb(){null=t;null->ch[0]=null->ch[1]=null->p=null->f=null;null->sz=0;}
void rotate(Node *x){
if(x==null || x->f==null) return;Node *y=x->f;Node *z=y->f;
int s= y->ch[1]==x,gs= z->ch[1]==y;x->f=z;
if(z!=null) z->ch[gs]=x;
y->ch[s]=x->ch[s^1];x->ch[s^1]->f=y;x->ch[s^1]=y;y->f=x;y->update();x->update();
swap(x->p,y->p);swap(x->val,y->val);//
}
Node *sta[N];
void splay(Node *x){
Node *y=x;int top=0;
while(y!=null) {sta[++top]=y;y=y->f;}
for(int i=top;i;i--) sta[i]->pushdown(null);
while(x->f!=null){
if(x->f->f==null) rotate(x);
else {
(x->f->f->ch[1]==x->f)^(x->f->ch[1]==x) ?rotate(x):rotate(x->f);rotate(x);
}
}
}
Node *access(Node *x){
Node *y=null;int k;
Ta:: Node *q,*e;
while(x!=null){
splay(x);
if(x->ch[1]!=null){
k=x->ch[0]->sz+2;
q=Val.kth(x->val,k);
Val.splay(q);
e=q->ch[0];
x->ch[1]->val=q;x->ch[1]->f=null;x->ch[1]->p=x;
q->ch[0]->f=Val.null;q->ch[0]=Val.null;q->update();
Val.splay(x->val=e);
}
if(y!=null){
k=x->val->sz;
q=Val.kth(x->val,k);
Val.splay(q);
q->ch[1]=y->val;q->ch[1]->f=q;q->update();
Val.splay(x->val);
}
x->ch[1]=y;y->p=null;y->f=x;x->update();
y=x;x=x->p;
}
return y;
}
void mkrt(Node *x){
Node *y=access(x);
y->reverse();y->val->reverse();
}
void lk(Node *x,Node *y){
mkrt(x);splay(x);x->p=y;access(x);
}
void rev(Node *x,Node *y){
mkrt(x);
access(y)->val->reverse();
}
void Add(Node *x,Node *y,int w){
mkrt(x);
access(y)->val->change(w);
}
ll Qsum(Node *x,Node *y){
mkrt(x);
return access(y)->val->sum;
}
ll Qmax(Node *x,Node *y){
mkrt(x);
return access(y)->val->mx;
}
ll Qmin(Node *x,Node *y){
mkrt(x);
return access(y)->val->mn;
}
}Lct;
Ta :: Node *B[N];
Tb :: Node *A[N];
int main(){
int i,j,x,y,z;
n=rd();m=rd();R=rd();
for(i=1;i<=n;++i) B[i]=Val.t+i;
for(i=1;i<=n;++i){
A[i]=Lct.t+i;A[i]->f=A[i]->p=A[i]->ch[0]=A[i]->ch[1]=Lct.null;
A[i]->val=Val.t+i;A[i]->sz=1;A[i]->val->sz=1;
A[i]->val->f=A[i]->val->ch[0]=A[i]->val->ch[1]=Val.null;
}
for(i=1;i<n;++i){x=rd();y=rd();Lct.lk(A[x],A[y]);}
while(m--){
scanf("%s",s);x=rd();y=rd();
if(s[0]=='I' && s[2]=='c'){z=rd();Lct.Add(A[x],A[y],z);}
else if(s[0]=='S') printf("%lld\n",Lct.Qsum(A[x],A[y]));
else if(s[0]=='M' && s[1]=='a') printf("%lld\n",Lct.Qmax(A[x],A[y]));
else if(s[0]=='M' && s[1]=='i') printf("%lld\n",Lct.Qmin(A[x],A[y]));
else Lct.rev(A[x],A[y]);
}
}