HDOJ 4010 Query on The Trees LCT

LCT:

分割、合并子树,路径上全部点的点权添加一个值,查询路径上点权的最大值

Query on The Trees

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)

Total Submission(s): 2582    Accepted Submission(s): 1208

Problem Description

We have met so many problems on the tree, so today we will have a query problem on a set of trees.

There are N nodes, each node will have a unique weight Wi. We will have four kinds of operations on it and you should solve them efficiently. Wish you have fun!

Input

There are multiple test cases in our dataset.

For each case, the first line contains only one integer N.(1 ≤ N ≤ 300000) The next N‐1 lines each contains two integers x, y which means there is an edge between them. It also means we will give you one tree initially.

The next line will contains N integers which means the weight Wi of each node. (0 ≤ Wi ≤ 3000)

The next line will contains an integer Q. (1 ≤ Q ≤ 300000) The next Q lines will start with an integer 1, 2, 3 or 4 means the kind of this operation.

1. Given two integer x, y, you should make a new edge between these two node x and y. So after this operation, two trees will be connected to a new one.

2. Given two integer x, y, you should find the tree in the tree set who contain node x, and you should make the node x be the root of this tree, and then you should cut the edge between node y and its parent. So after this operation, a tree will be separate
into two parts.

3. Given three integer w, x, y, for the x, y and all nodes between the path from x to y, you should increase their weight by w.

4. Given two integer x, y, you should check the node weights on the path between x and y, and you should output the maximum weight on it.

Output

For each query you should output the correct answer of it. If you find this query is an illegal operation, you should output ‐1.

You should output a blank line after each test case.

Sample Input

5
1 2
2 4
2 5
1 3
1 2 3 4 5
6
4 2 3
2 1 2
4 2 3
1 3 5
3 2 1 4
4 1 4

Sample Output

3
-1
7

Hint

We define the illegal situation of different operations:
In first operation: if node x and y belong to a same tree, we think it‘s illegal.
In second operation: if x = y or x and y not belong to a same tree, we think it‘s illegal.
In third operation: if x and y not belong to a same tree, we think it‘s illegal.
In fourth operation: if x and y not belong to a same tree, we think it‘s illegal.

Source

The 36th ACM/ICPC Asia Regional
Dalian Site —— Online Contest

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=330000;

int ch[maxn][2],pre[maxn],key[maxn];
int add[maxn],rev[maxn],Max[maxn];
bool rt[maxn];

void update_add(int r,int d)
{
  if(!r) return ;
  key[r]+=d;
  add[r]+=d;
  Max[r]+=d;
}

void update_rev(int r)
{
  if(!r) return ;
  swap(ch[r][0],ch[r][1]);
  rev[r]^=1;
}

void push_down(int r)
{
  if(add[r])
    {
      update_add(ch[r][0],add[r]);
      update_add(ch[r][1],add[r]);
      add[r]=0;
    }
  if(rev[r])
    {
      update_rev(ch[r][0]);
      update_rev(ch[r][1]);
      rev[r]=0;
    }
}

void push_up(int r)
{
  Max[r]=max(max(Max[ch[r][0]],Max[ch[r][1]]),key[r]);
}

void Rotate(int x)
{
  int y=pre[x],kind=(ch[y][1]==x);
  ch[y][kind]=ch[x][!kind];
  pre[ch[y][kind]]=y;
  pre[x]=pre[y];
  pre[y]=x;
  ch[x][!kind]=y;
  if(rt[y]) rt[y]=false,rt[x]=true;
  else ch[pre[x]][ch[pre[x]][1]==y]=x;
  push_up(y);
}

void P(int r)
{
  if(!rt[r]) P(pre[r]);
  push_down(r);
}

void Splay(int r)
{
  P(r);
  while(!rt[r])
    {
      int f=pre[r],ff=pre[f];
      if(rt[f]) Rotate(r);
      else if((ch[ff][1]==f)==(ch[f][1]==r)) Rotate(f),Rotate(r);
      else Rotate(r),Rotate(r);
    }
  push_up(r);
}

int Access(int x)
{
  int y=0;
  for(;x;x=pre[y=x])
    {
      Splay(x);
      rt[ch[x][1]]=true; rt[ch[x][1]=y]=false;
      push_up(x);
    }
  return y;
}

bool judge(int u,int v)
{
  while(pre[u]) u=pre[u];
  while(pre[v]) v=pre[v];
  return u==v;
}

void mroot(int r)
{
  Access(r);
  Splay(r);
  update_rev(r);
}

void lca(int &u,int &v)
{
  Access(v); v=0;
  while(u)
    {
      Splay(u);
      if(!pre[u]) return ;
      rt[ch[u][1]]=true;
      rt[ch[u][1]=v]=false;
      push_up(u);
      u=pre[v=u];
    }
}

void link(int u,int v)
{
  if(judge(u,v))
    {
      puts("-1");
      return ;
    }
  mroot(u);
  pre[u]=v;
}

void cut(int u,int v)
{
  if(u==v||!judge(u,v))
    {
      puts("-1");
      return ;
    }
  mroot(u);
  Splay(v);
  pre[ch[v][0]]=pre[v];
  pre[v]=0;
  rt[ch[v][0]]=true;
  ch[v][0]=0;
  push_up(v);
}

void Add(int u,int v,int w)
{
  if(!judge(u,v))
    {
      puts("-1"); return ;
    }
  lca(u,v);
  update_add(ch[u][1],w);
  update_add(v,w);
  key[u]+=w;
  push_up(u);
}

void query(int u,int v)
{
  if(!judge(u,v))
    {
      puts("-1");
      return ;
    }
  lca(u,v);
  printf("%d\n",max(max(Max[v],Max[ch[u][1]]),key[u]));
}

struct Edge
{
  int to,next;
}edge[maxn*2];

int Adj[maxn],Size=0;

void init()
{
  memset(Adj,-1,sizeof(Adj)); Size=0;
}

void add_edge(int u,int v)
{
  edge[Size].to=v;
  edge[Size].next=Adj[u];
  Adj[u]=Size++;
}

void dfs(int u)
{
  for(int i=Adj[u];~i;i=edge[i].next)
    {
      int v=edge[i].to;
      if(pre[v]!=0) continue;
      pre[v]=u;
      dfs(v);
    }
}
int n;

int main()
{
  while(scanf("%d",&n)!=EOF)
    {
      init();
      for(int i=0;i<n+10;i++)
        {
          pre[i]=0; ch[i][0]=ch[i][1]=0;
          rev[i]=0; add[i]=0; rt[i]=true;
        }

      for(int i=0;i<n-1;i++)
        {
          int u,v;
          scanf("%d%d",&u,&v);
          add_edge(u,v);
          add_edge(v,u);
        }
      pre[1]=-1; dfs(1); pre[1]=0;

      for(int i=1;i<=n;i++)
        {
          scanf("%d",key+i);
          Max[i]=key[i];
        }

      int q;
      scanf("%d",&q);
      while(q--)
        {
          int op;
          scanf("%d",&op);
          if(op==1)
            {
              int x,y;
              scanf("%d%d",&x,&y);
              link(x,y);
            }
          else if(op==2)
            {
              int x,y;
              scanf("%d%d",&x,&y);
              cut(x,y);
            }
          else if(op==3)
            {
              int x,y,w;
              scanf("%d%d%d",&w,&x,&y);
              Add(x,y,w);
            }
          else if(op==4)
            {
              int x,y;
              scanf("%d%d",&x,&y);
              query(x,y);
            }
        }
      putchar(10);
    }
  return 0;
}
时间: 2024-07-31 14:25:48

HDOJ 4010 Query on The Trees LCT的相关文章

hdu 4010 Query on the trees LCT

维护一个带点权的无向图森林,支持: 1.删边 2.加边 3.增加某条链所有点的点权 4.求某条链上点权的最大值 大概思路: 前两个需要更改根(即需要翻转标记) 第三个又需要一个标记,第四个每个节点记录该splay中以该节点为根的子树的最大点权. 收获: 1.对于splay前的标记下传可用递归写法, 虽然慢一点,但不容易写错. 2.access的过程中,在边转换完成后要更新节点信息. 3.对于寻找某子树的根,可以一直向上(会途径重边和轻边)找,这样比access+splay快很多,也很好写. 4.

HDU4010 Query on The Trees(LCT)

人生的第一道动态树,为了弄懂它的大致原理,需要具备一些前置技能,如Splay树,树链剖分的一些概念.在这里写下一些看各种论文时候的心得,下面的代码是拷贝的CLJ的模板,别人写的模板比较可靠也方便自己学习理解,然后一些概念的则是学习了一些论文,下面的内容可以看作对别人模板的理解心得,以及对论文的收获体会. LCT支持的主要是一种树路径上的操作,譬如说对u和v之间的路径上询问点权的和,询问点权的最大值,对所有点权加一个数,置为一个树等等.它和树链剖分不同的是,它支持将这个树上的边切掉,也支持将两个树

HDOJ 题目4010 Query on The Trees(Link Cut Tree连接,删边,路径点权加,路径点权最大值)

Query on The Trees Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 3602    Accepted Submission(s): 1587 Problem Description We have met so many problems on the tree, so today we will have a qu

HDU 4010 Query on The Trees (动态树)(Link-Cut-Tree)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4010 题意; 先给你一棵树,有 \(4\) 种操作: 1.如果 \(x\) 和 \(y\) 不在同一棵树上则在\(x-y\)连边. 2.如果 \(x\) 和 \(y\) 在同一棵树上并且 \(x!=y\) 则把 \(x\) 换为树根并把 \(y\) 和 \(y\) 的父亲分离. 3.如果 \(x\) 和 \(y\) 在同一棵树上则 \(x\) 到 \(y\) 的路径上所有的点权值\(+w\). 4

HDU 4010.Query on The Trees 解题报告

题意: 给出一颗树,有4种操作: 1.如果x和y不在同一棵树上则在xy连边 2.如果x和y在同一棵树上并且x!=y则把x换为树根并把y和y的父亲分离 3.如果x和y在同一棵树上则x到y的路径上所有的点权值+w 4.如果x和y在同一棵树上则输出x到y路径上的最大值 动态树入门题: #include <iostream> #include <cstdio> using namespace std; const int MAXN = 333333; struct node { int v

HDU 4010 Query on The Trees

题意: 一棵树  支持合并.分离.路径加权值.路径权值最大值 思路: LCT入门题  也是我的第一道-  代码来源于kuangbin巨巨  我只是整理出自己的风格留作模版- LCT比较好的入门资料是--<QTREE解法的一些研究> LCT基本做法就是先dfs建树  然后根据输入做上述4个操作 对于合并  就是把u转到树根  然后接在v上 对于分离  就是把u转到splay的根  然后切断与左子树的连接 对于路径加值  就是求出lca  然后包含u和v的子树以及lca点进行加值 对于路径求最值 

hdu 4010 Query on The Trees(动态树)

题意:给定一幅图的连接情况,给出每个点的权值,四种操作: 1 x y 连接x.y所在子树: 2 x y 将同一棵树上的x,y分离,形成两棵子树: 3 w x y 将x.y之间路径上的所有点权加w: 4 x y 查询x.y路径上点权的最大值: 动态树学习参考:http://www.cnblogs.com/BLADEVIL/p/3510997.html http://wenku.baidu.com/view/75906f160b4e767f5acfcedb http://m.blog.csdn.ne

HDU 4010 Query on The Trees(动态树)

题目链接: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路径上的最大值. 思路:1操作用link维护,2操作用cut,34操作先split(x,y),然后对y做tag,并且记录路径的max值. 1 #include<iost

Hdu 4010-Query on The Trees LCT,动态树

Query on The Trees Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 4091    Accepted Submission(s): 1774 Problem Description We have met so many problems on the tree, so today we will have a que