题目大意:给定一棵有根树,每个点有个权值,要求维护换根、单点修改、查询子树最小值
闲得我写了发LCT……
(这段时间咋净写LCT了。。。
每个节点开一个multiset记录一下所有虚边连接的子树的最小值
然后切换虚边的时候把原来的实边连接的子树扔进multiset,把新的实边连接的子树从multiset里删除就行了
时间复杂度O(nlog2n)
#include <set>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
int n,m,a[M];
namespace Link_Cut_Tree{
struct abcd{
abcd *ls,*rs,*fa;
multiset<int> s;
int min_val;
bool rev_mark;
abcd(int _);
void Push_Up();
void Push_Down();
void Reverse();
}*null=new abcd(0x7fffffff),*tree[M];
abcd :: abcd(int _)
{
ls=rs=fa=null;
s.insert(_);
min_val=_;
rev_mark=false;
}
void abcd :: Push_Up()
{
min_val=min(min(ls->min_val,rs->min_val),*(s.begin()));
}
void abcd :: Push_Down()
{
if(fa->ls==this||fa->rs==this)
fa->Push_Down();
if(rev_mark)
{
ls->Reverse();
rs->Reverse();
rev_mark=false;
}
}
void abcd :: Reverse()
{
swap(ls,rs);
rev_mark^=1;
}
void Zig(abcd *x)
{
abcd *y=x->fa;
y->ls=x->rs;
x->rs->fa=y;
x->rs=y;
x->fa=y->fa;
if(y==y->fa->ls)
y->fa->ls=x;
else if(y==y->fa->rs)
y->fa->rs=x;
y->fa=x;
y->Push_Up();
}
void Zag(abcd *x)
{
abcd *y=x->fa;
y->rs=x->ls;
x->ls->fa=y;
x->ls=y;
x->fa=y->fa;
if(y==y->fa->ls)
y->fa->ls=x;
else if(y==y->fa->rs)
y->fa->rs=x;
y->fa=x;
y->Push_Up();
}
void Splay(abcd *x)
{
x->Push_Down();
while(x->fa->ls==x||x->fa->rs==x)
{
abcd *y=x->fa,*z=y->fa;
if(x==y->ls)
{
if(y==z->ls)
Zig(y);
Zig(x);
}
else
{
if(y==z->rs)
Zag(y);
Zag(x);
}
}
x->Push_Up();
}
void Access(abcd *x)
{
abcd *y=null;
while(x!=null)
{
Splay(x);
if(x->rs!=null)
x->s.insert(x->rs->min_val);
x->rs=y;
if(y!=null)
x->s.erase(x->s.find(y->min_val));
x->Push_Up();
y=x;x=x->fa;
}
}
void Move_To_Root(abcd *x)
{
Access(x);
Splay(x);
x->Reverse();
}
}
struct edge{
int to,next;
}table[M<<1];
int head[M],tot;
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
void DFS(int x)
{
using namespace Link_Cut_Tree;
int i;
tree[x]=new abcd(a[x]);
for(i=head[x];i;i=table[i].next)
{
DFS(table[i].to);
tree[table[i].to]->fa=tree[x];
tree[x]->s.insert(tree[table[i].to]->min_val);
}
tree[x]->Push_Up();
}
int main()
{
using namespace Link_Cut_Tree;
int i,x,y;
char p[10];
cin>>n>>m;
for(i=1;i<=n;i++)
{
scanf("%d%d",&x,&a[i]);
if(x) Add(x,i);
}
DFS(1);
for(i=1;i<=m;i++)
{
scanf("%s",p);
if(p[0]=='V')
{
scanf("%d%d",&x,&y);
Access(tree[x]);
Splay(tree[x]);
tree[x]->s.erase(tree[x]->s.find(a[x]));
a[x]=y;
tree[x]->s.insert(a[x]);
tree[x]->Push_Up();
}
else if(p[0]=='E')
{
scanf("%d",&x);
Move_To_Root(tree[x]);
}
else
{
scanf("%d",&x);
Access(tree[x]);
Splay(tree[x]);
printf("%d\n",*(tree[x]->s.begin()));
}
}
return 0;
}