WZJ的数据结构(负十九) |
难度级别:E; 运行时间限制:3500ms; 运行空间限制:262144KB; 代码长度限制:2000000B |
试题描述 |
WZJ的数据结构中有很多都是关于树的。这让很多练习模板的同学还要找来找去很不爽,于是WZJ跟小伙伴们一块商量如何将这些题汇拢到一块去: WZJ:为了大家简单,我规定一开始是一棵有根树。 LZJ:那我一定得加上换根操作喽。 XJR:链信息修改,链信息增加,链信息翻倍,维护链信息的最大,最小,总和肯定很好做。 CHX:子树信息修改,子树信息增加,子树信息翻倍,维护子树信息的最大,最小,总和肯定也很好做。 WZJ:那这道题太水了吧,我们要能随时改变树的形态多好,加个换父亲的操作吧。 CHX:那也够水的,咱们再加一个查询父亲的操作吧。 LZJ:好不容易出了一道综合题,再加一个查询是否在子树内的操作吧。 XJR:一定要卡掉离线是必须的吧? |
输入 |
本题一共有22个操作: 第一行是N和M,表示有这棵树有N个点M个询问 然后是N-1行,每行x,y表示x-y有一条边 接下去是N行,每行是一个数字,表示每个点的权值 后面一行表示根 接下来是M行 第一个数字是K K=0 表示换根,后面x,表示把这棵树的根变成x K=1 表示点修改,后面x,y 表示把点x的权值改为y K=2 表示点增加,后面x,y 表示把点x的权值增加y K=3 表示点翻倍,后面x,y 表示把点x的权值翻y倍 K=4 表示点询问权值,后面x 表示询问这个点的权值 K=5 表示链修改,后面x,y,z,表示把这棵树中x-y的路径上点权值改成z K=6 表示链增加,后面x,y,z,表示把这棵树中x-y的路径上点权值增加z K=7 表示链翻倍,后面x,y,z,表示把这棵树中x-y的路径上点权值翻z倍 K=8 表示链询问min,后面x,y,表示询问这棵树中x-y的路径上点的min K=9 表示链询问max,后面x,y,表示询问这棵树中x-y的路径上点的max K=10 表示链询问sum,后面x,y,表示询问这棵树中x-y的路径上点的sum K=11 表示链询问siz,后面x,y,表示询问这棵树中x-y的路径上点的多少 K=12 表示子树修改,后面x,y,表示以x为根的子树的点权值改成y K=13 表示子树增加,后面x,y,表示以x为根的子树的点权值增加y K=14 表示子树翻倍,后面x,y,表示以x为根的子树的点权值翻y倍 K=15 表示子树询问min,后面x,表示询问以x为根的子树的点的min K=16 表示子树询问max,后面x,表示询问以x为根的子树的点的max K=17 表示子树询问sum,后面x,表示询问以x为根的子树的点的sum K=18 表示子树询问siz,后面x,表示询问以x为根的子树的点的多少 K=19 表示换父亲,后面x,y,表示把x的父亲换成y,如果y在x子树里不操作 K=20 表示询问子树,后面x,y, 表示询问y是否在x的子树内,输出true/false K=21 表示查询父亲,后面x,表示询问x的父亲的点权值,若没有父亲则输出-1 |
输出 |
对于每个询问输出一个答案,一行一个。 |
输入示例 |
5 30 1 2 2 3 3 4 4 5 1 -2 3 -1 2 3 0 2 1 2 2 2 3 1 3 5 5 4 2 5 3 2 5 6 1 4 3 7 4 5 2 8 5 3 9 2 5 10 1 5 11 3 4 12 4 -3 13 2 -1 14 3 4 15 2 16 2 17 4 18 4 19 4 1 20 1 4 21 1 14 1 4 15 3 18 1 19 5 3 21 5 13 3 1 4 5 17 2 |
输出示例 |
2 4 20 44 2 -16 28 -32 2 true 7 28 3 28 -63 -79 |
其他说明 |
N,M<=100000,所有计算结果保证在long long范围之内。 |
题解:水水哒AAA树全都搞定啦。(我如果把switch改成二分查找会不会快一点呢哈哈)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#define PAU putchar(' ')
#define ENT putchar('\n')
#define CH for(int d=0;d<=1;d++) if(ch[d])
using namespace std;
const int maxn=+,inf=<<;
struct info{long long mi,mx,siz,sm;}null=(info){inf,-inf,,};
struct tag{int mul,add;bool empty(){return (mul==&&add==);}}nulltag=(tag){,};
info operator+(const info&a,const info&b){
return (info){min(a.mi,b.mi),max(a.mx,b.mx),a.siz+b.siz,a.sm+b.sm};
}
info operator+(const info&a,const tag&b){
return a.siz?(info){a.mi*b.mul+b.add,a.mx*b.mul+b.add,a.siz,a.sm*b.mul+b.add*a.siz}:null;
}
tag operator+(const tag&a,const tag&b){
return (tag){a.mul*b.mul,a.add*b.mul+b.add};
}
struct snode{
snode*ch[],*fa;
info x,sm;tag od,all;
void init(){x=sm=null;od=all=nulltag;ch[]=ch[]=fa=NULL;return;}
snode(){x=sm=null;od=all=nulltag;ch[]=ch[]=fa=NULL;}
void addt(tag a){
od=od+a;all=all+a;x=x+a;sm=sm+a;return;
}
void down(){
if(!od.empty()){CH{ch[d]->addt(od);};od=nulltag;}return;
}
void update(){
sm=x;CH{sm=sm+ch[d]->sm;}return;
}
}Splay[maxn],*root[maxn];
int parent(snode*x,snode*&y){return (y=x->fa)?y->ch[]==x?:y->ch[]==x?:-:-;}
static void rotate(snode*x){
snode*y,*z;int d1=parent(x,y),d2=parent(y,z);
if(y->ch[d1]=x->ch[d1^]) y->ch[d1]->fa=y;
y->fa=x;x->fa=z;x->ch[d1^]=y;
if(d2!=-) z->ch[d2]=x;
y->update();return;
}
void pushdown(snode*x){
static snode*s[maxn];int top=;
for(snode*y;;x=y){
s[top++]=x;y=x->fa;
if(!y||(y->ch[]!=x&&y->ch[]!=x)) break;
} while(top--) s[top]->down();return;
}
static snode*splay(snode*x){
pushdown(x);snode*y,*z;int d1,d2;
while(true){
if((d1=parent(x,y))<) break;
if((d2=parent(y,z))<){rotate(x);break;}
if(d1==d2) rotate(y),rotate(x);
else rotate(x),rotate(x);
} x->update();return x;
}
snode*join(snode*x,snode*y){
if(!x)return y;if(!y)return x;
while(x->ch[]) x->down(),x=x->ch[];
splay(x)->ch[]=y;y->fa=x;x->update();return x;
}
struct node{
node*ch[],*fa,*s[];
info x,sm,sb,all;tag cha,tre;bool rev;
int id;
void revt(){
swap(ch[],ch[]);swap(s[],s[]);rev^=;return;
}
void chat(tag a){
x=x+a;sm=sm+a;cha=cha+a;all=sm+sb;return;
}
void tret(tag a){
tre=tre+a;sb=sb+a;all=sm+sb;if(root[id])root[id]->addt(a);return;
}
void down(){
if(rev){CH{ch[d]->revt();}rev=false;}
if(!cha.empty()){CH{ch[d]->chat(cha);}cha=nulltag;}
if(!tre.empty()){CH{ch[d]->tret(tre);}tre=nulltag;}
return;
}
void update(){
sm=x;sb=null;
if(root[id])sb=sb+root[id]->sm;
CH{sm=sm+ch[d]->sm;sb=sb+ch[d]->sb;}
all=sm+sb;
s[]=ch[]?ch[]->s[]:this;
s[]=ch[]?ch[]->s[]:this;
return;
}
}lct[maxn];
int parent(node*x,node*&y){return (y=x->fa)?y->ch[]==x?:y->ch[]==x?:-:-;}
void rotate(node*x){
node*y,*z;int d1=parent(x,y),d2=parent(y,z);
if(y->ch[d1]=x->ch[d1^]) y->ch[d1]->fa=y;
y->fa=x;x->fa=z;x->ch[d1^]=y;
if(d2!=-) z->ch[d2]=x;
y->update();return;
}
void pushdown(node*x){
static node*s[maxn];int top=;
for(node*y;;x=y){
s[top++]=x;y=x->fa;
if(!y||(y->ch[]!=x&&y->ch[]!=x)) break;
} while(top--) s[top]->down();return;
}
node*splay(node*x){
pushdown(x);node*y,*z;int d1,d2;
while(true){
if((d1=parent(x,y))<) break;
if((d2=parent(y,z))<){rotate(x);break;}
if(d1==d2) rotate(y),rotate(x);
else rotate(x),rotate(x);
} x->update();return x;
}
void add(snode*x,snode*&y,info tag){
x->init();x->x=tag;x->ch[]=y;if(y)y->fa=x;x->update();y=x;return;
}
void detach(node*x){
add(x->ch[]->s[]->id+Splay,root[x->id],x->ch[]->all);return;
}
void connect(node*x,node*y){
snode*p=y->s[]->id+Splay;splay(p);
if(p->ch[]) p->ch[]->fa=NULL;
if(p->ch[]) p->ch[]->fa=NULL;
root[x->id]=join(p->ch[],p->ch[]);
y->chat(p->all);y->tret(p->all);return;
}
node*access(node*x){
node*ret=NULL;
for(;x;x=x->fa){
if(splay(x)->ch[]) detach(x);
if(x->ch[]=ret) connect(x,ret);
(ret=x)->update();
} return ret;
}
void makeroot(int x){access(x+lct)->revt();return;}
void link(int x,int y){
access(lct+y);splay(lct+y)->ch[]=lct+x;makeroot(x);splay(lct+x)->fa=lct+y;return;
}
node*findfa(node*x){
x=splay(x)->ch[];
if(!x) return x;
else return x->s[];
}
int queryfa(int x){
node*t;access(x+lct);
if(!(t=findfa(x+lct))) return -;
else return t->x.sm;
}
int treeroot;
node*findtop(node*x){return splay(x)->s[];}
bool insub(int x,int y){
if(x==y||x==treeroot) return true;
access(y+lct);if(findtop(x+lct)==findtop(y+lct)) return true;
return false;
}
void changesub(int x,int y,tag t){
makeroot(x);access(lct+y);splay(lct+y);
lct[y].x=lct[y].x+t;
if(root[y]) root[y]->addt(t);
lct[y].update();return;
}
void changecha(int x,int y,tag t){
makeroot(x);access(lct+y)->chat(t);return;
}
info querycha(int x,int y){
makeroot(x);return access(lct+y)->sm;
}
info querysub(int x,int y){
makeroot(x);access(lct+y);splay(lct+y);return root[y]?lct[y].x+root[y]->sm:lct[y].x;
}
void cutfa(int x){
node*t=(access(lct+x),splay(lct+x));
t->ch[]=t->ch[]->fa=NULL;t->update();return;
}
void linkfa(int x,int fa){
access(fa+lct);splay(lct+fa);makeroot(x);splay(lct+x)->fa=lct+fa;lct[fa].update();
add(Splay+x,root[fa],lct[x].all);
return;
}
void splitfa(int r,int x,int fa){
makeroot(r);if((access(lct+x),access(lct+fa))==lct+x) return;
cutfa(x);linkfa(x,fa);return;
}
int n,Q,p1[maxn],p2[maxn],A[maxn];
void inittree(int*a){
for(int i=;i<=n;i++){
lct[i].id=i;
lct[i].s[]=lct[i].s[]=lct+i;
lct[i].x=lct[i].sm=lct[i].all=(info){a[i],a[i],,a[i]};
lct[i].cha=lct[i].tre=nulltag;
} return;
}
inline int read(){
int x=,sig=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')sig=-;ch=getchar();}
while(isdigit(ch))x=*x+ch-'',ch=getchar();
return x*=sig;
}
inline void write(long long x){
if(x==){putchar('');return;}if(x<)putchar('-'),x=-x;
int len=;static long long buf[];while(x)buf[len++]=x%,x/=;
for(int i=len-;i>=;i--)putchar(buf[i]+'');return;
}
void init(){
n=read();Q=read();
for(int i=;i<=n;i++) p1[i]=read(),p2[i]=read();
for(int i=;i<=n;i++) A[i]=read();
inittree(A);
for(int i=;i<=n;i++) link(p1[i],p2[i]);
treeroot=read();makeroot(treeroot);
return;
}
void work(){
int x,y,z,tp;
while(Q--){
tp=read();x=read();
switch(tp){
case :
makeroot(x),treeroot=x;
break;
case :
changecha(x,x,(tag){,read()});
break;
case :
changecha(x,x,(tag){,read()});
break;
case :
changecha(x,x,(tag){read(),});
break;
case :
write(querycha(x,x).mi);ENT;
break;
case :
y=read();changecha(x,y,(tag){,read()});
break;
case :
y=read();changecha(x,y,(tag){,read()});
break;
case :
y=read();changecha(x,y,(tag){read(),});
break;
case :
y=read();write(querycha(x,y).mi);ENT;
break;
case :
y=read();write(querycha(x,y).mx);ENT;
break;
case :
y=read();write(querycha(x,y).sm);ENT;
break;
case :
y=read();write(querycha(x,y).siz);ENT;
break;
case :
changesub(treeroot,x,(tag){,read()});
break;
case :
changesub(treeroot,x,(tag){,read()});
break;
case :
changesub(treeroot,x,(tag){read(),});
break;
case :
write(querysub(treeroot,x).mi);ENT;
break;
case :
write(querysub(treeroot,x).mx);ENT;
break;
case :
write(querysub(treeroot,x).sm);ENT;
break;
case :
write(querysub(treeroot,x).siz);ENT;
break;
case :
y=read();splitfa(treeroot,x,y);
break;
case :
y=read();if(insub(x,y)) puts("true");else puts("false");
break;
case :
write(queryfa(x));ENT;
break;
}
}
return;
}
void print(){
return;
}
int main(){init();work();print();return ;}