bzoj3083 遥远的国度

3083: 遥远的国度

Time Limit: 10 Sec  Memory Limit: 1280 MB
Submit: 4375  Solved: 1169
[Submit][Status][Discuss]

Description

zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。

问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。

Input

第1行两个整数n m,代表城市个数和操作数。
第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
第n+1行,有n个整数,代表所有点的初始防御值。
第n+2行一个整数 id,代表初始的首都为id。
第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。

Output

对于每个opt=3的操作,输出一行代表对应子树的最小点权值。

Sample Input

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

Sample Output

1
2
3
4
对于20%的数据,n<=1000 m<=1000。
对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。
对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。
对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。
对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。

Source

zhonghaoxi提供

分析:如果没有换根操作,这就是道树剖+线段树裸题了.

   有换根操作,一般并不会真正地去换根,只需要记录新的根在什么位置. 换根对于第二个操作其实是没有影响的. 对于点x的子树,则需要分类讨论.  3种情况:

   1. x是root的祖先,那么x往root方向的那个子树的答案不能被统计. 从root往x上跳,令跳到的比x深度大1的点为v,只需要查询

1~L[v] - 1,R[v] + 1 ~ n.  dfs序被分成两段.

   2.x不是root的祖先,那么x的子树没有变化.

   3.x = root,查询整棵树.

   大多数换根的题目都不需要真的去换根,分类讨论对其它操作的影响就好了.

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

using namespace std;

const int maxn = 200010,inf = 2147483647;
int n,m,a[maxn],head[maxn],to[maxn],nextt[maxn],tot = 1,root,id[maxn];
int son[maxn],fa[maxn][20],sizee[maxn],top[maxn],dep[maxn];
int minn[maxn << 1],tag[maxn << 1],newroot,pre[maxn],endd[maxn],dfs_clock;

void add(int x,int y)
{
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;
}

void dfs(int u,int faa)
{
    sizee[u] = 0;
    fa[u][0] = faa;
    dep[u] = dep[faa] + 1;
    for (int i = head[u]; i; i = nextt[i])
    {
        int v = to[i];
        if (v == faa)
            continue;
        dfs(v,u);
        sizee[u] += sizee[v];
        if (sizee[son[u]] < sizee[v])
            son[u] = v;
    }
}

void dfs2(int u,int topp)
{
    top[u] = topp;
    pre[u] = ++dfs_clock;
    id[dfs_clock] = u;
    if (son[u])
        dfs2(son[u],topp);
    for (int i = head[u]; i; i = nextt[i])
    {
        int v = to[i];
        if(v == fa[u][0] || v == son[u])
            continue;
        dfs2(v,v);
    }
    endd[u] = dfs_clock;
}

void pushup(int o)
{
    minn[o] = min(minn[o * 2],minn[o * 2 + 1]);
}

void pushdown(int o)
{
    if (tag[o])
    {
        tag[o * 2] = tag[o];
        tag[o * 2 + 1] = tag[o];
        minn[o * 2] = tag[o];
        minn[o * 2 + 1] = tag[o];
        tag[o] = 0;
    }
}

void build(int o,int l,int r)
{
    if (l == r)
    {
        minn[o] = a[id[l]];
        return;
    }
    int mid = (l + r) >> 1;
    build(o * 2,l,mid);
    build(o * 2 + 1,mid + 1,r);
    pushup(o);
}

void update(int o,int l,int r,int x,int y,int v)
{
    if (x <= l && r <= y)
    {
        minn[o] = v;
        tag[o] = v;
        return;
    }
    pushdown(o);
    int mid = (l + r) >> 1;
    if (x <= mid)
        update(o * 2,l,mid,x,y,v);
    if (y > mid)
        update(o * 2 + 1,mid + 1,r,x,y,v);
    pushup(o);
}

int lca(int x,int y)
{
    if (dep[x] < dep[y])
        swap(x,y);
    for (int i = 19; i >= 0; i--)
        if (dep[fa[x][i]] >= dep[y])
            x = fa[x][i];
    if (x == y)
        return x;
    for (int i = 19; i >= 0; i--)
        if (fa[x][i] != fa[y][i])
        {
            x = fa[x][i];
            y = fa[y][i];
        }
    return fa[x][0];
}

void Update(int x,int y,int d)
{
    while (top[x] != top[y])
    {
        if (dep[top[x]] < dep[top[y]])
            swap(x,y);
        update(1,1,n,pre[top[x]],pre[x],d);
        x = fa[top[x]][0];
    }
    if (dep[x] < dep[y])
        swap(x,y);
    update(1,1,n,pre[y],pre[x],d);
}

int query(int o,int l,int r,int x,int y)
{
    if (x <= l && r <= y)
        return minn[o];
    pushdown(o);
    int mid = (l + r) >> 1,res = inf;
    if (x <= mid)
        res = min(res,query(o * 2,l,mid,x,y));
    if (y > mid)
        res = min(res,query(o * 2 + 1,mid + 1,r,x,y));
    return res;
}

int jump(int x,int d)
{
    for (int i = 19; i >= 0; i--)
        if (dep[fa[x][i]] >= d)
            x = fa[x][i];
    return x;
}

int Query(int x)
{
    if (x == root)
        return query(1,1,n,1,n);
    int p = lca(x,root);
    if (x != p)
        return query(1,1,n,pre[x],endd[x]);
    int v = jump(root,dep[x] + 1);
    return min(query(1,1,n,endd[v] + 1,n),query(1,1,n,1,pre[v] - 1));
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i = 1; i < n; i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    for (int i = 1; i <= n; i++)
        scanf("%d",&a[i]);
    scanf("%d",&root);
    dfs(root,0);
    for (int j = 1; j <= 19; j++)
        for (int i = 1; i <= n; i++)
            fa[i][j] = fa[fa[i][j - 1]][j - 1];
    dfs2(root,root);
    build(1,1,n);
    for (int i = 1; i <= m; i++)
    {
        int opt;
        scanf("%d",&opt);
        if (opt == 1)
        {
            int t;
            scanf("%d",&t);
            root = t;
        }
        if (opt == 2)
        {
            int x,y,d;
            scanf("%d%d%d",&x,&y,&d);
            Update(x,y,d);
        }
        if (opt == 3)
        {
            int t;
            scanf("%d",&t);
            printf("%d
",Query(t));
        }
    }

    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/8537348.html