BZOJ3083: 遙遠的國度

3083: 遙遠的國度

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 839  Solved: 192
[Submit][Status]

Description

描述
zcwwzdjn在追殺十分sb的zhx,而zhx逃入了一個遙遠的國度。當zcwwzdjn準備進入遙遠的國度繼續追殺時,守護神RapiD阻攔了zcwwzdjn的去路,他須要zcwwzdjn完成任務後才能進入遙遠的國度繼續追殺。
php

問題是這樣的:遙遠的國度有n個城市,這些城市之間由一些路鏈接且這些城市構成 了一顆樹。這個國度有一個首都,咱們能夠把這個首都看作整棵樹的根,但遙遠的國度比較奇怪,首都是隨時有可能變爲另一個城市的。遙遠的國度的每一個城市有 一個防護值,有些時候RapiD會使得某兩個城市之間的路徑上的全部城市的防護值都變爲某個值。RapiD想知道在某個時候,若是把首都看作整棵樹的根的 話,那麼以某個城市爲根的子樹的全部城市的防護值最小是多少。因爲RapiD沒法解決這個問題,因此他攔住了zcwwzdjn但願他能幫忙。但 zcwwzdjn還要追殺sb的zhx,因此這個重大的問題就被轉交到了你的手上。api

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爲根的子樹中的最小防護值。
ui

Output


對於每一個opt=3的操做,輸出一行表明對應子樹的最小點權值。
spa

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。

HINT

Source

zhonghaoxi提供blog

 

orz鍾神的題,這題有個換根操做,可是仔細想一想,其實不「影響」dfs序的ip

樹鏈剖分獲得的也是一個合法的dfs序,對於換根操做,默認根節點爲1get

假設如今的根是root,那麼只有在root到1路徑上的點答案會受影響,其他的點就是查詢子樹就完了string

至於在root到1路徑上的點,發現,換根事後,所查詢的區間是(這有點難描述)hash

上張圖吧it

查詢的點是x

那麼除了紅色圈的那顆子樹之外,其他的點就是我要查詢的點,也就是裏x最近的屬於root到1路徑上的點,在dfs序上是連續的一段,那麼就查詢補集就行

仍是挺水的吧,,修改是一段區間,因此給個標記就行

注意root==x狀況就是整棵子樹

 
/*
Author:wuhuajun
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
using namespace std;
 
typedef long long ll;
typedef double dd;
const int maxn=200010;
const ll INF = (ll)1E14 + 9;
 
int h[maxn], n, m, top[maxn], lca[maxn][21], son[maxn], edge, sz[maxn], dep[maxn];
int L[maxn], R[maxn], root, num, x, y, tx, ty, t, opt;
ll val, a[maxn];
 
struct Edge
{
    int to, ne;
} e[maxn * 2];
 
struct Seg
{
    ll minn, same;
} seg[maxn << 2];
 
void close()
{
    exit(0);
}
 
void addedge(int x,int y)
{
    e[edge].to = y;
    e[edge].ne = h[x];
    h[x] = edge++;
}
 
void dfs(int k,int from)
{
    sz[k] = 1;
    dep[k] = dep[from] + 1;
    son[k] = 0;
    for (int p=h[k];p!=-1;p=e[p].ne)
    {
        int to = e[p].to;
        if (to == from) continue;
        lca[to][0] = k;
        for (int i=1;i<=20;i++)
            lca[to][i] = lca[lca[to][i-1]][i-1];
        dfs(to, k);
        sz[k] += sz[to];
        if (sz[to] > sz[son[k]]) son[k] = to;
    }
}
 
void build(int k,int from)
{
    L[k] = ++num;
    top[k] = from;
    if (son[k]) build(son[k], from);
    for (int p=h[k];p!=-1;p=e[p].ne)
    {
        int to = e[p].to;
        if (to != lca[k][0] && to != son[k])
            build(to, to);
    }
    R[k] = num;
}
 
int get_lca(int x,int y)
{
    if (dep[x] < dep[y]) swap(x, y);
    int depth = dep[x] - dep[y];
    for (int i=20;i>=0;i--)
        if (depth & (1 << i))
            x = lca[x][i];
    if (x == y) return x;
    for (int i=20;i>=0;i--)
    {
        if (lca[x][i] != lca[y][i])
        {
            x = lca[x][i];
            y = lca[y][i];
        }
    }
    return lca[x][0];
}
 
void pushup(int rt)
{
    seg[rt].minn = min(seg[rt<<1].minn, seg[rt<<1|1].minn);
}
 
void same(int rt,ll val)
{
    seg[rt].minn = val;
    seg[rt].same = val;
}
 
void pushdown(int rt)
{
    if (seg[rt].same)
    {
        same(rt << 1, seg[rt].same);
        same(rt << 1 | 1, seg[rt].same);
        seg[rt].same = 0;
    }
}
 
void change(int L,int R,ll val,int l,int r,int rt)
{
    if (L <= l && r <= R)
    {
        same(rt, val);
        return;
    }
    int mid = (l + r) >> 1;
    pushdown(rt);
    if (L <= mid)
        change(L,R,val,lson);
    if (mid + 1 <= R)
        change(L,R,val,rson);
    pushup(rt);
}
 
ll query(int L,int R,int l,int r,int rt)
{
    if (L > R) return INF;
    if (L <= l && r <= R)
    {
        return seg[rt].minn;
    }
    int mid = (l + r) >> 1;
    pushdown(rt);
    ll ans = INF;
    if (L <= mid)
        ans = min(ans, query(L,R,lson));
    if (mid + 1 <= R)
        ans = min(ans, query(L,R,rson));
    pushup(rt);
    return ans;
}
 
void cc()
{
    tx = top[x];
    ty = top[y];
    while (tx != ty)
    {
        if (dep[tx] < dep[ty])
        {
            swap(x, y);
            swap(tx, ty);
        }
        change(L[tx], L[x], val, 1, n, 1);
        x = lca[tx][0];
        tx = top[x];
    }
    if (dep[x] < dep[y])
        swap(x, y);
    change(L[y], L[x], val, 1, n, 1);
}
 
void work()
{
    if (root == x)
    {
        printf("%lld\n", seg[1].minn);//詢問全局的
        return;
    }
    t = get_lca(root, x);
    if (t != x) //表示不在它到根的路徑上
    {
        printf("%lld\n", query(L[x], R[x], 1, n, 1));
        return;
    }
    int depth = dep[root] - dep[x] - 1;
    int haha = root;
    for (int i=20;i>=0;i--)
        if (depth & (1 << i))
            haha = lca[haha][i];
    printf("%lld\n", min(query(1, L[haha] - 1, 1, n, 1), query(R[haha] + 1, n, 1, n, 1)) );
}
 
void init()
{
    scanf("%d %d",&n,&m);
    memset(h, -1, sizeof(h));
    for (int i=1;i<=n-1;i++)
    {
        scanf("%d %d",&x, &y);
        addedge(x, y);
        addedge(y, x);
    }
    for (int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    dfs(1, 0);
    build(1, 1);
    /*
    for (int i=1;i<=n;i++)
        printf("i:%d top:%d hash:%d son:%d\n",i, top[i], L[i], son[i]);
    close();
    */
    for (int i=1;i<=n;i++)
        change(L[i], L[i], a[i], 1, n, 1);
    scanf("%d",&root);
    while (m--)
    {
        scanf("%d",&opt);
        if (opt == 1) scanf("%d",&root);
        if (opt == 2)
        {
            scanf("%d %d %lld",&x,&y,&val);
            cc();
        }
        if (opt == 3)
        {
            scanf("%d",&x);
            work();
        }
    }
}
 
int main ()
{
    init();
    close();
    return 0;
}
相關文章
相關標籤/搜索