@desription@
In 11328, scientists in Country C developed a high-speed transmission channel that can take residents from one end of the channel to the other in a very short time. These channels are bidirectional.
The disadvantage is that this kind of transmission channel needs a lot of maintenance and repair.After planning, President C decided to build a new channel in M City. In M City, there were n transmission stations and 3 x (n_1) transmission channels, which were divided into three groups, each containing (n_1) channels.
When any set of channels is running, residents can travel from one station to another through the set of channels.That is, all the stations will be connected by the channels.The three groups of channels run in turn in the order of 1, 2 and 3, with repeated cycles.At any given time, there is only one set of transmission channels available.Formally, on day i, there are and only group ((i_1)mod3+1) channels running.
Access Globe, a renowned scientist in country C, is conducting a social investigation experiment to investigate information about users of transmission channels between two transmission stations.Access Globe's plan is as follows:
Select two transports a, b
On the first day, he starts from a, uses the running set of channels to get to b along the shortest path, and investigates information about users of all the channels he passes through
The next day, starting from b, he uses the running set of channels to get to a along the shortest path and investigates information about users of all the channels he passes through
On the third day, starting from a, he uses the running set of channels to get to b along the shortest path and investigates information about users of all the channels he passes through
Access Globe knows how many users are running on each transmission line.He wanted to find a pair of a and b to maximize the number of users through all channels throughout the experiment.Access Globe wants you to help him solve this simple little problem at CCF NOI 2018 Winter Camp.If you solve this problem successfully, Access Globe will give you a small gift - 100 points!
Input Format
The first line of the input file contains a positive integer n, which represents the number of transports numbered from 1 to n.
Lines 2 to n of the input file, each containing three numbers of u,v,w, indicate that there is a channel connecting u,v in the first set of channels, and the number of users at runtime is w.
Lines from (n+1) to (2n_1) of the input file consist of three numbers of u,v,w each, indicating that there is a channel connecting u and V in the second set of channels, and the number of runtime users is w.
Lines 2n through (3n_2) of the input file, each containing three numbers of u,v,w, indicate that there is a channel connecting u,v in the third group of channels, and the number of runtime users is w.
Output Format
The output file consists of one line and contains an integer representing the sum of the maximum number of users.
Example 1
input
5
1 2 2
1 3 0
1 4 1
4 5 7
1 2 0
2 3 1
2 4 1
2 5 3
1 5 2
2 3 8
3 4 5
4 5 1
output
27
explanation
One possible solution is to choose a=2,b=5, and the sum of such users is (3)+ (8+5+1)+ (2+1+7)=27.
Restrictions and conventions
For all data, 2 < n < 10 ^5, 0 < w < 10 ^12.
@solution@
[Title sticks to uoj because loj's mathematical formula is not sticky]
I'm afraid not all of them have become template/entry questions in the past year.But what kind of black technology was that year?
It should be said that the reason may be that edge Division has not been popularized at all.Why, it is clear that I came first with an algorithm similar to point division.
Okay, get to the point.We made the first tree t1, the second t2, and the third t3.
The title is simple: find a pair (u, v) to make t1.dis(u, v) + t2.dis(u, v) + t3.dis(u, v) the largest.
Simple solution: t1 edge division + t2 virtual tree + t3 maintenance diameter.
Consider reconstructing t1 and then dividing edges, since edge weights are good reconstructions because they are not point weights.
In each layer, the central edge divides the current connected block into two connected blocks.We consider all paths (u, v) that pass through the center edge, note that f[u] represents the distance of point u from the end of the center edge, and note that the length of the center edge is val.
For two u in different connected blocks, V has t1.dis(u, v) = f[u] + val + f[v].val is independent of u and v, so we only need to ask for a maximum of f[u] + f[v] + t2.dis(u, v) + t3.dis(u, v).
For each layer, a virtual tree corresponding to the connected blocks of this layer is built at t2.Enumerate lca for u and V as p, and revert the problem to f[u] + f[v] + t2.dep[u] + t2.dep[v] - 2*t2.dep[p] + t3.dis(u, v).
It can be found that t2.dep[p] has nothing to do with u, V but is actually the maximum required (f[u] + t2.dep[u]) + (f[v] + t2.dep[v]) + t3.dis(u, v).
For each point I in t3, we can create a new point i', I'connecting the edge of f[i] + t2.dep[i] to i, only t3.dis(u', v') is required.There is no need to connect this side in practice, just for the sake of thinking.
One conclusion is that for the set of two vertices S, T, one endpoint is selected in S, and the other endpoint is selected in T to get the maximum path value, which must be generated in the distance between the diameter endpoint in S and the diameter endpoint in T.
Thus, the diameters of the points in the corresponding t1 two connected blocks in the i subtree in t3 can be maintained by using the dp-like method in t2 dfs, and the optimum values of the answers can be maintained.The above conclusion can also be used to maintain the diameter.
t1 edge dividing, where the virtual tree runs at t2 for each layer of edge dividing, is the time complexity bottleneck O (nlog^2n).
By the way, lca is a way to have O(nlog n) preprocess O(1) queries (to rmq).This method is faster because the problem requires a lot of distance to solve.
@accepted code@
#include<cstdio> #include<algorithm> using namespace std; #define fi first #define se second typedef long long ll; typedef pair<int, int> pii; const int MAXN = 200000; int lg[MAXN + 5]; struct Graph{ struct edge{ bool tag; int to; ll dis; edge *nxt, *rev; }edges[2*MAXN + 5], *adj[MAXN + 5], *ecnt; int dfn[2*MAXN + 5], fir[MAXN + 5], dep[MAXN + 5], dcnt; int st[20][MAXN + 5]; ll dis[2*MAXN + 5]; Graph() {dcnt = 0, ecnt = &edges[0];} void addedge(int u, int v, ll w) { // printf("! %d %d %lld\n", u, v, w); edge *p = (++ecnt), *q = (++ecnt); p->to = v, p->dis = w, p->tag = false; p->nxt = adj[u], adj[u] = p; q->to = u, q->dis = w, q->tag = false; q->nxt = adj[v], adj[v] = q; q->rev = p, p->rev = q; } void dfs(int x, int f) { dep[x] = dep[f] + 1; dfn[++dcnt] = x, fir[x] = dcnt; for(edge *p=adj[x];p;p=p->nxt) { if( p->to == f ) continue; dis[p->to] = dis[x] + p->dis; dfs(p->to, x); dfn[++dcnt] = x; } } void get_st() { for(int i=1;i<=dcnt;i++) st[0][i] = dfn[i]; for(int j=1;j<20;j++) { int t = (1<<(j-1)); for(int i=1;i+t<=dcnt;i++) st[j][i] = (dep[st[j-1][i]] <= dep[st[j-1][i+t]]) ? st[j-1][i] : st[j-1][i+t]; } } void build() {dfs(1, 0), get_st();} int lca(int u, int v) { if( fir[u] > fir[v] ) swap(u, v); int k = lg[fir[v] - fir[u] + 1], l = (1<<k); return (dep[st[k][fir[u]]] <= dep[st[k][fir[v]-l+1]]) ? st[k][fir[u]] : st[k][fir[v]-l+1]; } ll dist(int u, int v) {return dis[u] + dis[v] - 2*dis[lca(u, v)];} }G1, G2, G3, G4; int n, m; void rebuild(const Graph &G1, Graph &G2, int x, int f) { int lst = -1; for(Graph::edge *p=G1.adj[x];p;p=p->nxt) { if( p->to == f ) continue; rebuild(G1, G2, p->to, x); if( lst == -1 ) { G2.addedge(x, p->to, p->dis); lst = x; } else { int s = (++m); G2.addedge(lst, s, 0); G2.addedge(s, p->to, p->dis); lst = s; } } } void init() { for(int i=2;i<=MAXN;i++) lg[i] = lg[i>>1] + 1; } int tid[MAXN + 5], dcnt = 0; void get_tid(Graph &G, int x, int f) { tid[x] = (++dcnt); for(Graph::edge *&p=G.adj[x];p;p=p->nxt) if( p->to != f ) get_tid(G, p->to, x); } int siz[MAXN + 5]; bool comp(Graph::edge *a, Graph::edge *b, int tot) { if( a == NULL ) return false; if( b == NULL ) return true; return max(siz[a->to], tot-siz[a->to]) < max(siz[b->to], tot-siz[b->to]); } Graph::edge *get_mid_edge(const Graph &G, int x, int f, int tot) { Graph::edge *ret = NULL; siz[x] = 1; for(Graph::edge *p=G.adj[x];p;p=p->nxt) { if( p->to == f || p->tag ) continue; Graph::edge *tmp = get_mid_edge(G, p->to, x, tot); siz[x] += siz[p->to]; if( tmp && comp(tmp, ret, tot) ) ret = tmp; if( comp(p, ret, tot) ) ret = p; } return ret; } bool cmp(int a, int b) { return tid[a] < tid[b]; } int arr[MAXN + 5], stk[MAXN + 5], type[MAXN + 5], acnt = 0, tp = 0, root; ll dis[MAXN + 5]; void dfs(const Graph &G, int x, int f, int t, ll d) { if( x <= n ) acnt++, arr[acnt] = x, type[x] = t, dis[x] = d + G2.dis[x]; for(Graph::edge *p=G.adj[x];p;p=p->nxt) { if( p->to == f || p->tag ) continue; dfs(G, p->to, x, t, d + p->dis); } } void insert(int x) { if( !tp ) { stk[++tp] = x; return ; } int l = G2.lca(stk[tp], x); if( l == stk[tp] ) { stk[++tp] = x; return ; } else { while( true ) { int x = stk[tp--]; if( tp && tid[stk[tp]] >= tid[l] ) { G2.addedge(stk[tp], x, G2.dist(stk[tp], x)); if( stk[tp] == l ) break; } else { stk[++tp] = l; G2.addedge(l, x, G2.dist(l, x)); break; } } stk[++tp] = x; } } void build_vtree(const Graph &G, Graph::edge *m) { G2.ecnt = &G2.edges[0]; acnt = 0, dfs(G, m->to, 0, -1, 0), dfs(G, m->rev->to, 0, 1, 0); sort(arr + 1, arr + acnt + 1, cmp); for(int i=1;i<=acnt;i++) insert(arr[i]); root = stk[1]; while( tp ) { int x = stk[tp--]; if( tp ) G2.addedge(x, stk[tp], G2.dist(x, stk[tp])); } } ll func(const int &a, const int &b, const int &c) { return dis[a] + dis[b] - 2*G2.dis[c] + G3.dist(a, b); } void update2(ll &ans, const pii &a, const pii &b, const int &x) { ans = max(ans, func(a.fi, b.fi, x)), ans = max(ans, func(a.fi, b.se, x)); ans = max(ans, func(a.se, b.fi, x)), ans = max(ans, func(a.se, b.se, x)); } void update4(pii &a, const int &b, const int &x) { ll p = func(a.fi, b, x), q = func(a.se, b, x), r = func(a.fi, a.se, x); if( p >= q && p >= r ) a.se = b; else if( q >= p && q >= r ) a.fi = b; } void update1(pair<pii, pii>&a, const pair<pii, pii>&b, ll &ans, const int &x) { if( a.fi.fi ) { if( b.se.fi ) update2(ans, a.fi, b.se, x); if( b.fi.fi ) update4(a.fi, b.fi.fi, x), update4(a.fi, b.fi.se, x); } else a.fi = b.fi; if( a.se.fi ) { if( b.fi.fi ) update2(ans, a.se, b.fi, x); if( b.se.fi ) update4(a.se, b.se.fi, x), update4(a.se, b.se.se, x); } else a.se = b.se; } pair<pii, pii>dfs1(int x, int f, ll &ans) { pair<pii, pii>ret = make_pair(make_pair(0, 0), make_pair(0, 0)); if( type[x] ) { if( type[x] == 1 ) ret.first = make_pair(x, x); if( type[x] == -1 ) ret.second = make_pair(x, x); } for(Graph::edge *&p=G2.adj[x];p;p=p->nxt) { if( p->to == f ) continue; pair<pii, pii>tmp = dfs1(p->to, x, ans); update1(ret, tmp, ans, x); } return ret; } ll divide(const Graph &G, int x, int tot) { Graph::edge *m = get_mid_edge(G, x, 0, tot); if( m == NULL ) return 0; m->tag = m->rev->tag = true; build_vtree(G, m); ll ans = 0; dfs1(root, 0, ans); ans += m->dis; for(int i=1;i<=acnt;i++) type[arr[i]] = 0; return max(ans, max(divide(G, m->to, siz[m->to]), divide(G, m->rev->to, tot-siz[m->to]))); } int main() { init(); scanf("%d", &n); for(int i=1;i<n;i++) { int u, v; ll w; scanf("%d%d%lld", &u, &v, &w); G1.addedge(u, v, w); } for(int i=1;i<n;i++) { int u, v; ll w; scanf("%d%d%lld", &u, &v, &w); G2.addedge(u, v, w); } for(int i=1;i<n;i++) { int u, v; ll w; scanf("%d%d%lld", &u, &v, &w); G3.addedge(u, v, w); } m = n, rebuild(G1, G4, 1, 0); G2.build(), G3.build(), G4.build(); get_tid(G2, 1, 0); printf("%lld\n", divide(G4, 1, m)); }
@details@
Writing is relatively long, but it is not really difficult. Write it easily according to your ideas.
There's hardly a debug at all.