TZOJ 8472 : Tree (重鏈剖分+線段樹) POJ 3237

holy_crap發表於2024-03-26

今天學了重鏈剖分,正好可以補題

描述
You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:

● CHANGE i v Change the weight of the ith edge to v
● NEGATE a b Negate the weight of every edge on the path from a to b
● QUERY a b Find the maximum weight of edges on the path from a to b

輸入
The input contains multiple test cases. The first line of input contains an integer t (t ≤ 20), the number of test cases. Then follow the test cases.
Each test case is preceded by an empty line. The first nonempty line of its contains N (N ≤ 10,000). The next N − 1 lines each contains three integers a, b and c, describing an edge connecting nodes a and b with weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “DONE” ends the test case.
輸出
For each “QUERY” instruction, output the result on a separate line.
樣例輸入

1
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE

樣例輸出

1
3

樣例輸入2

1
4
1 2 1
2 3 2
1 4 4
QUERY 1 2
QUERY 1 3
QUERY 2 3
QUERY 2 4
NEGATE 3 4
QUERY 1 2
QUERY 1 3
QUERY 2 3
QUERY 4 1
DONE

樣例輸出2

1
2
2
4
-1
-1
-2
-4

思路:
題目要求
1.樹上路徑取反
2.樹上路徑查詢
3.樹上單點修改
既然是維護最值的樹上路徑修改,就可以用重鏈剖分將樹變為鏈,鏈進行區間維護可以用線段樹;
洛谷模板題P3384
董曉演算法【模板】輕重鏈剖分/樹鏈剖分

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
#define io ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mem(a, b) memset((a), (b), sizeof(a))
#define inf 0x3f3f3f3f
#define infl 0x3f3f3f3f3f3f3f3f
#define seed 13331
#define MOD 1000000007
#define ls u<<1
#define rs u<<1|1
mt19937 rnd(time(0));
const ll N = 1e4+7;

int n,idx,top[N],dep[N],fa[N],son[N],siz[N];
int id[N],nw[N],w[N];

map<array<int,2>,int> ma;
map<int,vector<int>> v;
struct node{
    int l,r,mx,mn,tag;
}tr[N<<2];

void sb()
{
    v.clear();
    idx = 0;
    mem(top,0);
    mem(dep,0);
    mem(fa,0);
    mem(son,0);
    mem(siz,0);
    mem(id,0);
    mem(nw,0);
    mem(w,0);
    mem(tr,0);
    ma.clear();
    //sb初始化
}
//重鏈剖分
int dfs1(int u,int f)
{
    siz[u] = 1;
    fa[u] = f, dep[u] = dep[f] + 1;
    w[u] = ma[{u,f}];
    for(auto c:v[u]) if(f!=c)
    {
        dfs1(c,u);
        siz[u] += siz[c];
        if(siz[c]>siz[son[u]])   son[u] = c;
    }
    return siz[u];
}
void dfs2(int u,int f)
{
    top[u] = f; id[u] = ++idx;nw[idx] = w[u];
    if(!son[u]) return;
    dfs2(son[u],f);//先給重鏈編號,所以重鏈上點有連續的編號
    for(auto c:v[u])    if(c!=fa[u]&&c!=son[u])   
        dfs2(c,c); 
}

void sw(int u)
{
    tr[u].mn = -tr[u].mn;
    tr[u].mx = -tr[u].mx;
    swap(tr[u].mx,tr[u].mn);
}

void push_down(int u)
{
    if(tr[u].tag)
    {
        sw(ls);     
        sw(rs);
        tr[u].tag = 0;
        tr[ls].tag ^= 1;
        tr[rs].tag ^= 1;
    }
}
void push_up(int u)
{
    tr[u].mx = max(tr[ls].mx,tr[rs].mx);
    tr[u].mn = min(tr[ls].mn,tr[rs].mn);
}
void build(int u, int l, int r)
{
    tr[u] = {l,r};
    int mid = l+r>>1;
    if(l==r)
    {
        tr[u] = {l,r,nw[l],nw[l]};
        return;
    }
    build(ls,l,mid);
    build(rs,mid+1,r);
    push_up(u);
}
void update(int u, int p, int k)
{
    if(tr[u].l == tr[u].r)
    {
        tr[u].mx = tr[u].mn = k;
        return;
    }
    push_down(u);
    int mid = tr[u].l+tr[u].r>>1;
    if(p<=mid)  update(ls,p,k);
    if(p>mid)   update(rs,p,k);
    push_up(u);
}
void negate1(int u,int l,int r)
{
    if(l<=tr[u].l&&tr[u].r<=r)  
    {
        sw(u);
        tr[u].tag ^= 1;
        return;
    }
    push_down(u);
    int mid = tr[u].l+tr[u].r>>1;
    if(l<=mid)  negate1(ls,l,r);
    if(r>mid)   negate1(rs,l,r);
    push_up(u);
}
int query(int u,int l,int r)
{
    if(l<=tr[u].l&&tr[u].r<=r)      
        return tr[u].mx;
    push_down(u);
    int mid = tr[u].l+tr[u].r>>1;
    int mx = -inf;  
    if(l<=mid)  mx = max(mx,query(ls,l,r));
    if(r>mid)   mx = max(mx,query(rs,l,r));
    if(mx == -inf) return 0;
    return mx;
}
int query(int u,int v)
{
    int res = -inf;
    while(top[u]!=top[v])
    {
        if(dep[top[u]]<dep[top[v]])   swap(u,v);
        res = max(res,query(1,id[top[u]],id[u]));
        u = fa[top[u]];
    }
    if(u==v)    return (res==-inf?0:res);
    if(dep[u]<dep[v])   swap(u,v);
    v = son[v];//排除lca
    res = max(res,query(1,id[v],id[u]));
    return (res==-inf?0:res);
}
void negate1(int u,int v)
{
    while(top[u]!=top[v])
    {
        if(dep[top[u]]<dep[top[v]])   swap(u,v);
        negate1(1,id[top[u]],id[u]);
        u = fa[top[u]];
    }
    if(u==v)    return;
    if(dep[u]<dep[v])   swap(u,v);
    v = son[v];//排除lca
    negate1(1,id[v],id[u]);
}
void solve(ll i_)
{
    cin>>n;
    sb();
    vector<array<int,2>> t;
    for(int i=1;i<n;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        v[a].push_back(b);
        v[b].push_back(a);
        ma[{a,b}] = ma[{b,a}] = c;
        t.push_back({a,b});
    }
    //將邊權w放在u->v的v節點上,查詢路徑轉換成查詢 除lca以外的途徑點
    dfs1(1,1);
    dfs2(1,1);
    build(1,1,n);
    string s;
    while(cin>>s,s!="DONE")
    {
        int a,b;
        cin>>a>>b;
        if(s[0]=='Q')
            cout<<query(a,b)<<endl;
        if(s[0]=='C')
        {
            auto r = t[a-1];
            int p = dep[r[0]]>dep[r[1]]?r[0]:r[1]; //取深度較大的點
            update(1,id[p],b);
        }
        if(s[0]=='N')
            negate1(a,b);
    }
}
signed main()
{
    io;ll T=1,i_;
    
    cin>>T;
    for(i_=1;i_<=T;i_++)
        solve(i_);
    return 0;
}

相關文章