// Cay nho - GRAPE
// NOI Singapore 2022 Task 4: Grapevine
#include <bits/stdc++.h>
#define ll long long
#define ld long double
#define f1(i,n) for(int i=1;i<=n;i++)
#define __file_name ""
using namespace std;
const ll maxn=1e5+5, inf=1e16;
struct Lazy{
long long data = 0;
Lazy(){};
Lazy(long long data): data(data){};
Lazy operator+(const Lazy &rhs) const{
// Push a lazy down
return Lazy(data + rhs.data);
}
};
struct Value{
long long data = 1e18;
Value(){};
Value(long long data): data(data){};
Value operator+(const Value &rhs) const{
// Merge two nodes
return Value(min(data, rhs.data));
}
Value operator+(const Lazy &rhs) const{
// Apply lazy to node
return Value(data + rhs.data);
}
};
template<class T, class U>
struct SegmentTree{
int n;
vector<T> st;
vector<U> lazy;
SegmentTree(){};
SegmentTree(int n): n(n), st(4*n+1), lazy(4*n+1){};
inline void down(int idx){
st[idx*2] = st[idx*2] + lazy[idx];
lazy[idx*2] = lazy[idx*2] + lazy[idx];
st[idx*2+1] = st[idx*2+1] + lazy[idx];
lazy[idx*2+1] = lazy[idx*2+1] + lazy[idx];
lazy[idx] = U();
}
void _upd1(int idx, int l, int r, int i, const T &v){
if(i < l || r < i) return;
if(l == r){
st[idx] = v;
return;
}
down(idx);
int mid = (l + r) / 2;
_upd1(idx*2, l, mid, i, v);
_upd1(idx*2+1, mid+1, r, i, v);
st[idx] = st[idx*2] + st[idx*2+1];
}
inline void updatePoint(int position, const T &value){
_upd1(1,1,n,position,value);
}
void _upd2(int idx, int l, int r, int u, int v, const U &w){
if(v < l || r < u) return;
if(u <= l && r <= v){
st[idx] = st[idx] + w;
lazy[idx] = lazy[idx] + w;
return;
}
down(idx);
int mid = (l + r) / 2;
_upd2(idx*2, l, mid, u, v, w);
_upd2(idx*2+1, mid+1, r, u, v, w);
st[idx] = st[idx*2] + st[idx*2+1];
}
inline void updateRange(int left_, int right_, const U &value){
_upd2(1,1,n,left_, right_, value);
}
T _get(int idx, int l, int r, int u, int v){
if(v < l || r < u) return T();
if(u <= l && r <= v) return st[idx];
down(idx);
int mid = (l + r) / 2;
return _get(idx*2, l, mid, u, v) + _get(idx*2+1, mid+1, r, u, v);
}
inline T getRange(int left_, int right_){
return _get(1,1,n,left_, right_);
}
};
#define SegTree SegmentTree<Value,Lazy>
int n, q, wei[maxn];
vector<pair<int,int>> G[maxn];
map<int, int> edgeID[maxn];
bool haveGrape[maxn];
int sz[maxn], parc[maxn], depc[maxn];
bool del[maxn];
void dfs_sz(int u, int p){
sz[u] = 1;
for(pair<int,int> e: G[u]){
int c = e.first;
if(c != p && !del[c]){
dfs_sz(c, u);
sz[u] += sz[c];
}
}
}
int find_centroid(int u, int p, int N){
for(pair<int,int> e: G[u]){
int c = e.first;
if(c != p && !del[c] && sz[c] > N / 2){
return find_centroid(c, u, N);
}
}
return u;
}
vector<int> sp[maxn], ep[maxn], nodes[maxn];
int timer;
SegTree st[maxn];
void build_euler(int u, int p, int root, ll cdep){
int idx = nodes[root].size();
nodes[root].push_back(u);
st[root].updatePoint(timer, cdep + inf);
sp[root].push_back(timer++);
ep[root].push_back(0);
for(pair<int,int> e: G[u]){
int c = e.first, w = wei[e.second];
if(c != p && !del[c]){
build_euler(c, u, root, cdep + w);
}
}
ep[root][idx] = timer - 1;
}
void build_cen(int u, int p = 0, int dd = 0){
dfs_sz(u, 0);
int root = find_centroid(u, 0, sz[u]);
parc[root] = p;
depc[root] = dd;
st[root] = SegTree(sz[u]);
timer = 1;
build_euler(root, 0, root, 0);
vector<pair<int,int>> tmpnode;
for(int i=0;i<nodes[root].size();i++){
tmpnode.push_back({nodes[root][i], i});
}
sort(tmpnode.begin(), tmpnode.end());
vector<int> tmpv;
nodes[root].clear();
for(pair<int,int> item: tmpnode){
nodes[root].push_back(item.first);
tmpv.push_back(sp[root][item.second]);
}
swap(sp[root], tmpv);
tmpv.clear();
for(pair<int,int> item: tmpnode){
tmpv.push_back(ep[root][item.second]);
}
swap(ep[root], tmpv);
del[root] = true;
for(pair<int,int> e: G[root]){
int c = e.first;
if(!del[c]) {
build_cen(c, root, depc[root] + 1);
}
}
}
//int par[17][maxn], udep[maxn];
//ll depth[maxn];
//void binlift(int u, int p){
// par[0][u] = p;
// for(int i=1;i<17;i++) par[i][u] = par[i-1][par[i-1][u]];
// for(pair<int,int> e: G[u]){
// int c = e.first, w = wei[e.second];
// if(c != p){
// depth[c] = depth[u] + w;
// udep[c] = udep[u] + 1;
// binlift(c, u);
// }
// }
//}
//
//int LCA(int u, int v){
// if(udep[u] < udep[v]) swap(u, v);
// int l = udep[u] - udep[v];
// for(int i=0;i<17;i++){
// if(l >> i & 1) u = par[i][u];
// }
// if(u == v) return u;
// for(int i=16;i>=0;i--){
// if(par[i][u] != par[i][v]){
// u = par[i][u];
// v = par[i][v];
// }
// }
// return par[0][u];
//}
ll getDist(int root, int u){
int idx = lower_bound(nodes[root].begin(), nodes[root].end(), u) - nodes[root].begin();
ll res = st[root].getRange(sp[root][idx], sp[root][idx]).data;
if(!haveGrape[u]) res -= inf;
return res;
}
int main(){
ios_base::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
if(fopen(__file_name ".inp", "r")){
freopen(__file_name ".inp", "r", stdin);
freopen(__file_name ".out", "w", stdout);
}
// code here
cin >> n >> q;
f1(i,n-1){
int u, v, w; cin >> u >> v >> w;
wei[i] = w;
G[u].push_back({v, i});
G[v].push_back({u, i});
edgeID[u][v] = edgeID[v][u] = i;
}
// binlift(1, 0);
build_cen(1);
while(q--){
int tp; cin >> tp;
if(tp == 1){
int u; cin >> u;
ll ans = inf;
int v = u;
while(v != 0){
// cout << v << " -> " << u << ' ' << ans << ' ' << getDist(v, u) << ' ' << st[v].st[1].data << '\n';
ans = min(ans, getDist(v, u) + st[v].st[1].data);
v = parc[v];
}
cout << (ans >= 1e15 ? -1LL : ans) << '\n';
}else if(tp == 2){
int u; cin >> u;
int v = u;
while(v != 0){
int idx = lower_bound(nodes[v].begin(), nodes[v].end(), u) - nodes[v].begin();
ll newVal = (haveGrape[u] ? inf : -inf);
st[v].updateRange(sp[v][idx], sp[v][idx], newVal);
// cout << "! " << v << " => " << u << ' ' << parc[v] << ' ' << newVal << '\n';
v = parc[v];
}
haveGrape[u] = !haveGrape[u];
}else{
int u, v, w; cin >> u >> v >> w;
int eidx = edgeID[u][v];
ll diff = w - wei[eidx];
wei[eidx] = w;
if(depc[u] > depc[v]) swap(u, v);
// move from u up
int root = u;
while(root != 0){
int uidx = lower_bound(nodes[root].begin(), nodes[root].end(), u) - nodes[root].begin();
int vidx = lower_bound(nodes[root].begin(), nodes[root].end(), v) - nodes[root].begin();
if(sp[root][vidx] <= sp[root][uidx] && ep[root][uidx] <= ep[root][vidx]){
swap(uidx, vidx);
}
// u is parent of v in root
st[root].updateRange(sp[root][vidx], ep[root][vidx], diff);
root = parc[root];
}
}
}
return 0;
}
컴파일 시 표준 에러 (stderr) 메시지
Main.cpp: In function 'int main()':
Main.cpp:218:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
218 | freopen(__file_name ".inp", "r", stdin);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Main.cpp:219:16: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
219 | freopen(__file_name ".out", "w", stdout);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |