遥远的国度

Posted captain1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了遥远的国度相关的知识,希望对你有一定的参考价值。

传送门

这是一道好题啊……没有换根的话就是树剖板子题,但是加上换根怎么办?

每次暴力重构dfs序?那不T死你……(突然想到自己动态点分治每次重新跑一遍点分治的sd思路)

那么我们肯定是老套路,寻找修改根结点之后的不变量。我们先以最开始给定的根,来确定dfs序和其他一切一切的树剖基本工作。

把路径全部修改成一个权值没什么难度,主要是看换根之后的访问问题。

我们分三种情况讨论:

1.根结点就是当前访问的点。

这种情况非常好解决,直接输出整体最小值即可。

2.根结点不在当前访问的节点的子树内。

这个也很容易,因为根结点如果不在当前访问的子树内,那么这个点的子树原来是什么样现在还是什么样,没什么变化,直接访问即可。

3.根结点在当前访问的子树内。

这个稍微复杂,不过仔细思考之后发现,那就是这个点当前的子树,应该是整棵树减去当然根结点所在的子树。

好像最稳定的方法是使用倍增求出来哪一个儿子是root所在的子树的根,之后访问其他的即可。不过我没有采取这种方式,而是用了一种更加暴力的方法:因为树剖保证了每棵子树内的dfs序一定是连续的,所以我们去掉这一段,直接访问剩下两端的最小值即可。怎么确定呢?我们枚举每一个子树,因为dfs序是连续的,所以如果root的dfs序在dfn[x] ~ dfn[x] + size[x] - 1之内,那么它就在这个子树之内。

这个方法其实挺不稳定的,很容易被菊花图卡……不过其实跑的还挺快……

看一下代码。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<queue>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar(‘
‘)

using namespace std;
typedef long long ll;
const int M = 100005;
const int INF = 1000000009;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < 0 || ch > 9)
    {
    if(ch == -) op = -1;
    ch = getchar();
    }
    while(ch >= 0 && ch <= 9)
    {
    ans *= 10;
    ans += ch - 0;
    ch = getchar();
    }
    return ans * op;
}

struct edge
{
    int next,to;
}e[M<<1];

struct seg
{
    int v,lazy;
}t[M<<2];

int n,m,u,v,root,op,x,y,head[M],hson[M],size[M],dep[M],dfn[M],ecnt,fa[M],top[M],idx,def[M],rk[M];
int nl,nr;

void add(int x,int y)
{
    e[++ecnt].to = y;
    e[ecnt].next = head[x];
    head[x] = ecnt;
}

void dfs1(int x,int f,int depth)
{
    size[x] = 1,fa[x] = f,dep[x] = depth;
    int maxson = -1;
    for(int i = head[x];i;i = e[i].next)
    {
    if(e[i].to == f) continue;
    dfs1(e[i].to,x,depth+1);
    size[x] += size[e[i].to];
    if(size[e[i].to] > maxson) maxson = size[e[i].to],hson[x] = e[i].to;
    }
}

void dfs2(int x,int t)
{
    top[x] = t,dfn[x] = ++idx,rk[idx] = def[x];
    if(!hson[x]) return;
    dfs2(hson[x],t);
    for(int i = head[x];i;i = e[i].next)
    {
    if(e[i].to == fa[x] || e[i].to == hson[x]) continue;
    dfs2(e[i].to,e[i].to);
    }
}

void build(int p,int l,int r)
{
    if(l == r)
    {
    t[p].v = rk[l];
    return;
    }
    int mid = (l+r) >> 1;
    build(p<<1,l,mid),build(p<<1|1,mid+1,r);
    t[p].v = min(t[p<<1].v,t[p<<1|1].v);
}

void pushdown(int p,int l,int r)
{
    int mid = (l+r) >> 1;
    t[p<<1].lazy = t[p<<1|1].lazy = t[p].lazy;
    t[p<<1].v = t[p<<1|1].v = t[p].lazy;
    t[p].lazy = 0;
}

void modify(int p,int l,int r,int kl,int kr,int val)
{
    if(l == kl && r == kr)
    {
    t[p].v = t[p].lazy = val;
    return;
    }
    int mid = (l+r) >> 1;
    if(t[p].lazy) pushdown(p,l,r);
    if(kr <= mid) modify(p<<1,l,mid,kl,kr,val);
    else if(kl > mid) modify(p<<1|1,mid+1,r,kl,kr,val);
    else modify(p<<1,l,mid,kl,mid,val),modify(p<<1|1,mid+1,r,mid+1,kr,val);
    t[p].v = min(t[p<<1].v,t[p<<1|1].v);
}

int query(int p,int l,int r,int kl,int kr)
{
    if(kl > kr) return INF;
    if(l == kl && r == kr) return t[p].v;
    int mid = (l+r) >> 1;
    if(t[p].lazy) pushdown(p,l,r);
    if(kr <= mid) return query(p<<1,l,mid,kl,kr);
    else if(kl > mid) return query(p<<1|1,mid+1,r,kl,kr);
    else return min(query(p<<1,l,mid,kl,mid),query(p<<1|1,mid+1,r,mid+1,kr));
}

int lca(int x,int y,bool flag,int val)
{
    while(top[x] != top[y])
    {
    if(dep[top[x]] < dep[top[y]]) swap(x,y);
    if(flag) modify(1,1,n,dfn[top[x]],dfn[x],val);
    x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x,y);
    if(flag) modify(1,1,n,dfn[x],dfn[y],val);
    return x;
}

void findson(int x)
{
    for(int i = head[x];i;i = e[i].next)
    {
    if(e[i].to == fa[x]) continue;
    if(dfn[e[i].to] <= dfn[root] && dfn[e[i].to] + size[e[i].to] - 1 >= dfn[root])
    {
        nl = dfn[e[i].to],nr = dfn[e[i].to] + size[e[i].to] - 1;
        return;
    }
    }
}

int main()
{
    n = read(),m = read();
    rep(i,1,n-1) x = read(),y = read(),add(x,y),add(y,x);
    rep(i,1,n) def[i] = read();
    root = read();
    dfs1(root,0,1),dfs2(root,root),build(1,1,n);
    //rep(i,1,n) printf("%d ",dfn[i]);enter;
    rep(i,1,m)
    {
    op = read();
    if(op == 1) root = read();
    else if(op == 2) x = read(),y = read(),v = read(),lca(x,y,1,v);
    else if(op == 3)
    {
        //printf("#%d %d
",root,lca(x,root,0,0));
        x = read();
        if(x == root) printf("%d
",t[1].v);
        else if(lca(x,root,0,0) != x) printf("%d
",query(1,1,n,dfn[x],dfn[x] + size[x] - 1));
        else if(lca(x,root,0,0) == x)
        {
        findson(x);
        //printf("!%d %d
",nl,nr);
        int g = min(query(1,1,n,1,nl-1),query(1,1,n,nr+1,n));
        //g = min(query(1,1,n,dfn[x],dfn[x]),g);
        printf("%d
",g);
        }    
    }
    }
    return 0;
}

 

以上是关于遥远的国度的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 3083: 遥远的国度

BZOJ 3083 遥远的国度(树链剖分+LCA)

bzoj3083遥远的国度(树链剖分+线段树)

BZOJ3083: 遥远的国度

遥远的国度 bzoj3083

BZOJ 3083 遥远的国度