您的位置:首页 > 产品设计 > UI/UE

HDU 4010 Query on The Trees(动态树)

2013-03-27 22:32 309 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4010

题意:一棵树,四种操作:

(1)若x和y不在一棵树上,将x和y连边;

(2)若x和y在一棵树上,将x变成树根,将y从x树上分离;

(3)若x和y在一棵树上,将x到y路径上的所有值增加det;

(4)若x和y在一棵树上,输出x到y路径上的最大值。

思路:一、由于出现的多棵树,那么每次操作之前都要判断询问的两个节点是不是在一棵树上,比如对于操作(2)(3)(4)来说都要保证x和y在一棵树上时操作才是合法的;对于(1)则x和y不能在一棵树上。首先,我们用一个函数makeroot(x)表示将x设为x所在树(是树而不是树链)的根。其实就是将x到其所在树的树根的路径上的边全部反向,那么x就会成为根。我们先access(x),那么x就与root连在一起,然后splay(x),x就调整到了根的位置,但是还不是跟,因为root现在其实在x的左孩子或者左孩子的子孙,x的右孩子现在为null,因为我们access(x)的时候将x与其右孩子断开了;那么现在我们将x的左孩子和右孩子互换(其实就是将右孩子设为左孩子,左孩子设为null),那么此时x就成为了真正的树根;

二、有了makeroot(x)之后,我们怎么判断x和y是不是在一个树上呢?首先makeroot(x),x成为树根;x的父节点为null。接着access(y),splay(y),试想,若x和y不在一棵树上,那么此时y的操作与x无任何关系,此时x的父节点还是null;但是,y若与x在一棵树上就不同了,现在y成了树根(只是调整到了树根的位置,x才是真正的树根),那么x必然是y的左孩子或者左孩子的子孙,即x的父节点不为空。据此,我们根据x的父节点是不是为null可判断x和y是否在一棵树上;其实用makeroot(y)代替access(y),splay(y)也是可以的,不好的地方就是这样就改变了树的真实结构;

三、现在我们说说对于题目中的四个操作怎么做:

(1)makeroot(x),access(y),splay(y),x和y若不在一棵树上,此时x的父节点为null,因此直接将x的父节点设为y;

(2)makeroot(x),access(y),splay(y),x和y若在一棵树上,y的右孩子实际是y的子孙,加上y也就是y所在子树,y的左孩子是y的祖宗节点,因此将y的左孩子置为null,同时将y左孩子的父节点置为null。

(3)(4)差不多,增加标志就可以。

struct node
{
int det,val,Max,isReversed;
node *c[2],*f;

void add(int x)
{
val+=x;
det+=x;
Max+=x;
}

void reverse()
{
isReversed^=1;
swap(c[0],c[1]);
}
};

node a
,*nullNode;
int n;

void pushUp(node *p)
{
p->Max=max(p->val,max(p->c[0]->Max,p->c[1]->Max));
}

void pushDown(node *p)
{
if(p->det)
{
if(p->c[0]!=nullNode) p->c[0]->add(p->det);
if(p->c[1]!=nullNode) p->c[1]->add(p->det);
p->det=0;
}
if(p->isReversed)
{
if(p->c[0]!=nullNode) p->c[0]->reverse();
if(p->c[1]!=nullNode) p->c[1]->reverse();
p->isReversed=0;
}
}

void rotate(node *p,int k)
{
node *q=p->f;
q->c[k]=p->c[!k];
if(p->c[!k]!=nullNode) p->c[!k]->f=q;
p->c[!k]=q;
p->f=q->f;
if(q->f!=nullNode)
{
if(p->f->c[0]==q) p->f->c[0]=p;
if(p->f->c[1]==q) p->f->c[1]=p;
}
q->f=p;
pushUp(q);
}

int isRoot(node *p)
{
return p->f==nullNode||p->f->c[0]!=p&&p->f->c[1]!=p;
}

void splay(node *p)
{
pushDown(p);
while (!isRoot(p))
{
if(isRoot(p->f))
{
pushDown(p->f);
pushDown(p);
if(p==p->f->c[0]) rotate(p,0);
else rotate(p,1);
}
else
{
pushDown(p->f->f);
pushDown(p->f);
pushDown(p);
if(p->f->f->c[0]==p->f)
{
if(p->f->c[0]==p) rotate(p->f,0);
else rotate(p,1);
rotate(p,0);
}
else
{
if(p->f->c[1]==p) rotate(p->f,1);
else rotate(p,0);
rotate(p,1);
}
}
}
pushUp(p);
}

node* access(node *p)
{
node *q=nullNode;
while(p!=nullNode)
{
splay(p);
p->c[1]=q;
pushUp(p);
q=p;
p=p->f;
}
return q;
}

void makeRoot(int x)
{
access(a+x);
splay(a+x);
a[x].reverse();
}

void join(int x,int y)
{
if(x==y)
{
puts("-1");
return;
}
makeRoot(x);access(a+y);splay(a+y);
if(a[x].f==nullNode) a[x].f=a+y;
else puts("-1");
}

void cut(int x,int y)
{
makeRoot(x);access(a+y);splay(a+y);
if(a[x].f==nullNode) puts("-1");
else
{
a[y].c[0]->f=nullNode;
a[y].c[0]=nullNode;
pushUp(a+y);
}
}

void change(int x,int y,int val)
{
makeRoot(y);access(a+x);splay(a+x);
if(a[y].f==nullNode)
{
puts("-1");
return;
}

access(a+x);
node *lca=access(a+y);
if(lca->c[1]!=nullNode) lca->c[1]->add(val);
lca->val+=val;
if(a+x!=lca&&(a+x)!=nullNode) splay(a+x),a[x].add(val);
pushUp(lca);
}

int query(int x,int y)
{
if(x==y) return a[x].val;
makeRoot(y);access(a+x);splay(a+x);
if(a[y].f==nullNode) return -1;

access(a+x);
node *lca=access(a+y);
int ans;
if(a+x!=nullNode) splay(a+x);
if(a+x!=lca)
{
ans=max(lca->c[1]->Max,a[x].Max);
ans=max(ans,lca->val);
}
else
{
ans=max(lca->c[1]->Max,lca->val);
}
return ans;
}

struct Node
{
int v,next;
};

Node edges
;
int head
,e;

void Add(int u,int v)
{
edges[e].v=v;
edges[e].next=head[u];
head[u]=e++;

edges[e].v=u;
edges[e].next=head[v];
head[v]=e++;
}

void build()
{
queue<int> Q;
Q.push(1);
int i,u,v;
while(!Q.empty())
{
u=Q.front();
Q.pop();

for(i=head[u];i!=-1;i=edges[i].next)
{
v=edges[i].v;
if(a+v==a[u].f) continue;
a[v].f=a+u;
Q.push(v);
}
}

}

int get()
{
int x=0,flag=1;
char c=getchar();
while(!isdigit(c)) c=getchar();
if(c=='-')
{
flag=-1,c=getchar();
while(!isdigit(c)) c=getchar();
}
while(isdigit(c))
{
x=x*10+c-'0';
c=getchar();
}
return x*flag;
}

void init()
{
nullNode=new node();
nullNode->isReversed=0;
nullNode->det=0;
nullNode->Max=-INF;
nullNode->val=-INF;
nullNode->c[0]=nullNode->c[1]=nullNode->f=nullNode;
int i,u,v,dis;
clr(head,-1);
e=0;
FOR1(i,n-1) u=get(),v=get(),Add(u,v);
FOR1(i,n)
{
dis=get();
a[i].c[0]=a[i].c[1]=a[i].f=nullNode;
a[i].isReversed=0;
a[i].det=0;
a[i].Max=a[i].val=dis;
}
build();
}

int main()
{
while(scanf("%d",&n)!=-1)
{
init();
int a,b,c,op,m=get();
while(m--)
{
op=get();
if(op==1) a=get(),b=get(),join(a,b);
else if(op==2) a=get(),b=get(),cut(a,b);
else if(op==3) c=get(),a=get(),b=get(),change(a,b,c);
else a=get(),b=get(),PR(query(a,b));
}
puts("");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: