今天學了重鏈剖分,正好可以補題
描述
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;
}