题意:
小 F 堕入了梦魇的世界,一只巨大的魔爪,或者说,一棵根节点为 1 的有根树,每个节点有
一个危险值 wi w i 。
小 F 不会自己从梦境中醒来,她要在梦境中切断自己与梦魇的联系,才能逃离这个世界。
每次,小 F 都是从 1 号节点进入这个世界。
她要去编号为 x1,x2...xk x 1 , x 2 . . . x k 的节点上切断联系。
她希望知道她要经过的所有节点的危险度之和最小是多少(多次经过只算一次)。
支持:
1. 1xw 1 x w 在编号为 x x 的点下加一个危险值为 w w 的叶节点。
2. 2xw 2 x w 令 fax f a x 为此刻 x x 的父节点标号,在边 (fax,x) ( f a x , x ) 上新建一个危险值为 w w 的节点 z z , 原
来的边变为 (fax,z) ( f a x , z ) 和 (z,x) ( z , x )
3. 3k 3 k x1x2...xk x 1 x 2 . . . x k 表示一次询问,意义如题面所示。
题解:
虚树,同时用Splay维护dfs序,LCT维护路径和即可。
#include
using namespace std;
typedef long long LL;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 :*ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
inline void W(LL x) {
static int buf[50];
if(!x) {putchar('0'); return;}
if(x<0) {putchar('-'); x=-x;}
while(x) {buf[++buf[0]]=x%10; x/=10;}
while(buf[0]) {putchar(buf[buf[0]--]+'0');}
}
const int N=4e5+50;
const int INF=0x3f3f3f3f;
struct LCT* lct;
struct Splay* splay;
int n,m,cnt,w[N],fa[N],dfn[N];
LL lst;
vector <int> edge[N];
struct Splay {
struct node;
static node* null;
struct node {
node *lc,*rc,*fa;
int dep,dep_mn,tag_add,sze;
inline void add(int v) {
dep+=v; dep_mn+=v; tag_add+=v;
}
inline void pushdown() {
if(!tag_add) return;
(lc!=null) && (lc->add(tag_add),0);
(rc!=null) && (rc->add(tag_add),0);
tag_add=0;
}
inline void upt() {
sze=lc->sze+rc->sze+1;
dep_mn=min(lc->dep_mn,rc->dep_mn);
dep_mn=min(dep_mn,dep);
}
}Pool[N],*pos[N],*pool=Pool,*rt;
inline node* newnode(int v) {
node *t=++pool;
t->lc=t->rc=t->fa=null;
t->dep=t->dep_mn=v;
t->sze=1;
return t;
}
inline bool which(node *x) {return x->fa->lc==x;}
inline void rotate(node *x) {
node *y=x->fa, *z=y->fa;
if(z!=null) ((z->lc==y) ? (z->lc) : (z->rc))=x;
x->fa=z; y->fa=x;
if(y->lc==x) {
node *b=x->rc;
x->rc=y; y->lc=b;
if(b!=null) b->fa=y;
} else {
node *b=x->lc;
x->lc=y; y->rc=b;
if(b!=null) b->fa=y;
} y->upt(); x->upt();
}
inline void splay(node *x,node *tar) {
static node* stk[N]; static int tl;
stk[tl=1]=x;
for(node *y=x; y->fa!=null; y=y->fa) stk[++tl]=y->fa;
for(int i=tl; i; i--) stk[i]->pushdown();
while(x->fa!=tar) {
node *y=x->fa;
if(y->fa!=tar) {
if(which(y)==which(x)) rotate(y);
else rotate(x);
} rotate(x);
}
if(tar==null) rt=x;
}
inline void inc(node *&x,node *fa,node *t) {
if(x==null) {
x=t; x->fa=fa; return;
}
inc(x->rc,x,t);
}
inline void dfs(int x,int f) {
pos[x]=newnode(f ? pos[f]->dep+1 : 1);
inc(rt,null,pos[x]);
splay(pos[x],null);
for(auto v:edge[x])
if(v!=f) dfs(v,x);
}
inline void init() {
null=Pool; rt=null;
null->lc=null->rc=null->fa=null;
null->dep_mn=null->dep=INF;
for(int i=2;i<=n;i++)
edge[fa[i]].push_back(i);
inc(rt,null,newnode(0));
dfs(1,0);
inc(rt,null,newnode(0));
splay(pool,null);
}
inline void set(int x,int f) {
splay(pos[f],null);
pos[x]=newnode(pos[f]->dep+1);
}
inline node* suf_rt() {
node *p=rt->rc;
while(p->lc!=null) p->pushdown(), p=p->lc;
return p;
}
inline void link(int x,int f) {
splay(pos[f],null);
splay(suf_rt(),rt);
rt->rc->lc=pos[x];
pos[x]->fa=rt->rc;
rt->rc->upt();
rt->upt();
}
inline int get_dfn(int x) {
splay(pos[x],null);
return pos[x]->lc->sze;
}
inline node* get_pre(int x) {
splay(pos[x],null);
node *p=pos[x]->lc;
while(p->rc!=null) p->pushdown(), p=p->rc;
return splay(p,null), p;
}
inline node* get_nxt(int x) {
splay(pos[x],null);
int lim=pos[x]->dep;
node *p=pos[x]->rc;
while(p!=null) {
p->pushdown();
if(p->lc->dep_mn<=lim) p=p->lc;
else if(p->dep<=lim) break;
else p=p->rc;
}
return splay(p,null), p;
}
inline void modify(int now,int x) {
node *pre=get_pre(x);
node *nxt=get_nxt(x);
splay(pre,null);
splay(nxt,rt);
pre->rc->lc->add(-1);
splay(pos[x],rt);
pos[now]->fa=pos[x];
pos[x]->lc=pos[now];
pos[x]->upt();
rt->upt();
}
inline int get_dep(int x) {
splay(pos[x],null);
return pos[x]->dep;
}
};
Splay::node* Splay::null;
struct LCT {
struct node;
static node* null;
struct node {
node *lc,*rc,*fa;
int v; LL sum;
inline void upt() {
sum=lc->sum+rc->sum+v;
}
}Pool[N],*pos[N],*pool=Pool;
inline node* newnode(int v) {
node *t=++pool;
t->lc=t->rc=t->fa=null;
t->v=t->sum=v;
return t;
}
inline bool isroot(node *x) {return x->fa->lc!=x && x->fa->rc!=x;}
inline bool which(node *x) {return x->fa->lc==x;}
inline void rotate(node *x) {
node *y=x->fa, *z=y->fa;
if(!isroot(y)) ((z->lc==y) ? z->lc : z->rc)=x;
x->fa=z; y->fa=x;
if(y->lc==x) {
node *b=x->rc;
x->rc=y; y->lc=b;
if(b!=null) b->fa=y;
} else {
node *b=x->lc;
x->lc=y; y->rc=b;
if(b!=null) b->fa=y;
} y->upt(); x->upt();
}
inline void splay(node *x) {
while(!isroot(x)) {
node *y=x->fa;
if(!isroot(y)) {
if(which(y)==which(x)) rotate(y);
else rotate(x);
} rotate(x);
}
}
inline int access(node *x) {
node *lst=x;
for(node *y=null; x!=null; y=x, x=x->fa) {
lst=x; splay(x);
x->rc=y; x->upt();
}
return lst-Pool;
}
inline void init() {
null=Pool; null->lc=null->rc=null->fa=null;
for(int i=1;i<=n;i++)
pos[i]=newnode(w[i]);
for(int i=2;i<=n;i++)
pos[i]->fa=pos[fa[i]];
}
inline void link(int x,int f) {
splay(pos[x]);
pos[x]->fa=pos[f];
}
inline void cut(int x,int f) {
access(pos[f]); splay(pos[x]);
pos[x]->fa=null;
}
inline int get_lca(int x,int y) {
access(pos[x]);
return access(pos[y]);
}
inline void set(int x,int ww) {pos[x]=newnode(ww);}
inline LL get_sum(int x,int f) {
LL rs=0;
access(pos[x]); splay(pos[x]);
rs+=pos[x]->sum;
access(pos[f]); splay(pos[f]);
rs-=pos[f]->sum;
return rs;
}
};
LCT::node* LCT::null;
inline int decode(int v) {return (v+lst)%cnt+1;}
int main() {
splay=new Splay;
lct=new LCT;
n=rd(), m=rd(), cnt=n;
for(int i=1;i<=n;i++) w[i]=rd();
for(int i=2;i<=n;i++) fa[i]=rd();
lct->init();
splay->init();
for(int T=1; T<=m; T++) {
int op=rd();
if(op==1) {
int x=decode(rd()), ww=rd(); ++cnt;
fa[cnt]=x;
lct->set(cnt,ww);
lct->link(cnt,x);
splay->set(cnt,x);
splay->link(cnt,x);
} else if(op==2) {
int x=decode(rd()), ww=rd(); ++cnt;
int f=fa[x];
lct->set(cnt,ww);
lct->cut(x,f);
lct->link(cnt,f);
lct->link(x,cnt);
splay->set(cnt,f);
splay->modify(cnt,x);
fa[cnt]=f; fa[x]=cnt;
} else {
static int stk[N],tl,vir_point[N*2],vc,vir_fa[N];
vc=rd();
for(int i=1;i<=vc;i++)
vir_point[i]=decode(rd());
vir_point[++vc]=1;
for(int i=1;i<=vc;i++)
dfn[vir_point[i]]=splay->get_dfn(vir_point[i]);
sort(vir_point+1, vir_point+vc+1, [](int x,int y){return dfn[x]for(int i=vc;i>1;i--)
vir_point[++vc]=lct->get_lca(vir_point[i],vir_point[i-1]);
for(int i=1;i<=vc;i++) {
int u=vir_point[i];
dfn[u]=splay->get_dfn(u);
vir_fa[u]=0;
}
sort(vir_point+1, vir_point+vc+1, [](int x,int y){return dfn[x]1,vir_point+vc+1)-vir_point-1;
stk[tl=1]=vir_point[1];
for(int i=2;i<=vc;i++) {
int u=vir_point[i];
int lca=lct->get_lca(stk[tl],u);
while(stk[tl]!=lca) --tl;
vir_fa[u]=lca; stk[++tl]=u;
}
lst=0;
for(int i=1;i<=vc;i++) {
int u=vir_point[i];
if(vir_fa[u])
lst+=lct->get_sum(u,vir_fa[u]);
}
lst+=w[1];
W(lst); putchar('\n');
}
}
}