3306: 树

时间限制: 10 Sec  内存限制: 256 MB

题目描述

给定一棵大小为 n 的有根点权树,支持以下操作: 
  • 换根 
  • 修改点权  
     • 查询子树最小值

输入

  第一行两个整数 n, Q ,分别表示树的大小和操作数。 
  接下来n行,每行两个整数f,v,第i+1行的两个数表示点i的父亲和点i的权。保证f < i。如 果f = 0,那么i为根。输入数据保证只有i = 1时,f = 0。 
  接下来 m 行,为以下格式中的一种: 
  • V x y表示把点x的权改为y 
  • E x 表示把有根树的根改为点 x 
  • Q x 表示查询点 x 的子树最小值

输出

  对于每个 Q ,输出子树最小值。

样例输入

3 7
0 1
1 2
1 3
Q 1
V 1 6
Q 1
V 2 5
Q 1
V 3 4
Q 1

样例输出

1
2
3
4

提示

  对于 100% 的数据:n, Q ≤ 10^5。

思路:

看到这个题时,有没有脑子里一下子蹦出这样一个念头:这个题用线段树做!

对,的确是这样。但有人又要问了:线段树怎么用?

碍于各种原因,我们在这先不说线段树的做法,到后卖弄我们开始学线段树的时候,我们再来用线段树A这道题。

我们在前面一直在刷lca题嘛,所以我们把这道题弱化一下:只有换根和查询最小值的操作。

那这样有没有感觉这个题变简单了很多啊?

好,那我们就来秒一下这个题吧!

具体思路:我们考虑这样一个问题:若果没有换跟操作,那我们是不是就可以用一遍dfs求出这道题了?

那我们接下来考虑根节点s与查询节点x的关系。

如果:lca(s,x)!=x,那答案就是以x为根的子树的最小值

若s==x,那x即为最小值。

若lca(x,s)==x,那答案就是除去点x包含点s的子数的最小值。

前两种情况可以预先处理前缀和后缀。

由于一个子树在dfs序上对应的是一段区间,那这样剩下的部分是不是就是一段的前缀+一段后缀啊?!

所以我们优先处理前缀后缀的最小值来解决问题。

代码:

#include<vector>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 1000
using namespace std;
vector<int>vec[N];
int fa[N][N],A[N],B[N];
int deep[N],C[N],en[N],cnt,a[N];
int n,m,top[N],ans,dfn[N],st[N],x,y;
string s;
int lca(int x,int y)
{
    if(deep[x]>deep[y])
     swap(x,y);
    ;i>=;i--)
      if(deep[fa[y][i]]>=deep[x]) y=fa[y][i];
    if(x==y) return x;
    ;i>=;i--)
     if(fa[y][i]!=fa[x][i])
       x=fa[x][i],y=fa[y][i];
    ];
}
void dfs(int x)
{
    st[x]=++cnt;
    dfn[cnt]=x;
    C[x]=a[x];
    ;i<vec[x].size();i++)
    {
        deep[vec[x][i]]=deep[x]+;
        dfs(vec[x][i]);
        C[x]=min(C[x],C[vec[x][i]]);
    }
    en[x]=cnt;
}
int main()
{
    scanf("%d%d",&n,&m);
    ;i<=n;i++)
    {
        scanf(],&a[i]);
        vec[fa[i][]].push_back(i);
    }
    ]=;dfs(S);
    A[]=B[n+]=1e9;
    ;i<=n;i++)
     A[i]=min(A[i-],a[dfn[i]]);
    ;i--)
     B[i]=min(B[i+],a[dfn[i]]);
    int T,t;
    ;i<=m;i++)
    {
        cin>>s;
        ]=='E') scanf("%d",&S);
        else
        {
            scanf("%d",&T);
            t=lca(S,T);
            ]);
            else if(t!=T) printf("%d\n",C[T]);
            else
            {
                int ss=S;
                ;i>=;i--)
                 if(deep[fa[ss][i]]>deep[T]) ss=fa[ss][i];
                printf(],B[en[ss]+]));
            }
        }
    }
    ;
}

最新文章

  1. H5实现摇一摇技术总结
  2. [Android]Android端ORM框架——RapidORM(v2.1)
  3. Java中引用类 strong reference .SoftReference 、 WeakReference 和 PhantomReference的区别
  4. ruby include和exclude区别
  5. Java管道流
  6. 单片机特殊功能寄存器(SFR)
  7. QML学习笔记之二
  8. vim使用手册
  9. hive优化之------控制hive任务中的map数和reduce数
  10. 放开Linux内核对用户进程可打开文件数和TCP连接的限制
  11. 宏 #,##,_ _VA_ARGS_ _
  12. Android 打开系统相册和系统视
  13. 五个典型的JavaScript面试题
  14. SSE &amp;&amp; WebSockets
  15. 静默安装MSSQL
  16. php截取等长UFT8中英文混合字串
  17. MySQL并发复制系列二:多线程复制 2016
  18. Codeforces 626D Jerry&#39;s Protest(暴力枚举+概率)
  19. 洛谷P2486 染色
  20. Altium Designer Summer 09换成中文步骤

热门文章

  1. destoon 屏蔽会员组,让个人,游客不显示
  2. windows下配置Nginx支持php
  3. Mac远程访问Ubuntu
  4. HDU:4185-Oil Skimming
  5. Linux下ioctl函数理解
  6. Linux学习-核心与核心模块
  7. Python动态属性和特性(一)
  8. (手写)mybatis 核心配置文件和接口不在同一包下的解决方案
  9. 简述 yield和yield from关键字
  10. 如何用字体在网页中画icon