https://www.luogu.org/problemnew/show/P2680
题解:
二分一个答案x之后,只需要考虑m条路径中路径长度大于x的那些路径,并对那些路径求一个交。设m中最长路径为l,则只需判断路径交中的边是否存在一条边e使得e.w>=l-x。如何求交?其实我们树链剖分之后,只需用一个差分数组来维护每条边被多少条路径覆盖,只需考虑被覆盖的路径条数等于当前考虑的路径条数的边即可
复杂度分析:差分数组的复杂度仅为O(1),总时间复杂度为O(nlognlogw),w<=3e8。由于差分数组和树链剖分的常数都较小,因此可以通过该题
#include<iostream> #include<cstring> #include<cstdio> #include<vector> #define clr(a,b) memset(a,b,sizeof(a)) #define maxn 300000 #define max(a,b) (a>b?a:b) #define min(a,b) (a<b?a:b) using namespace std; int n,m; inline void swap(int &a,int &b) { int t=a; a=b; b=t; } struct EDGE { int u,v,w,next; } edge[maxn*2+10]; int head[maxn+10],pp; void adde(int u,int v,int w) { edge[++pp]=(EDGE) { u,v,w,head[u] }; head[u]=pp; } int de[maxn+10],sz[maxn+10],fa[maxn+10],hs[maxn+10],w[maxn+10]; int que[maxn+10],he,ta; vector<int>ch[maxn+10]; int top[maxn+10],id[maxn+10],s[maxn+10],tot; void bfs() { que[he=ta=1]=1; while(he<=ta) { int u=que[he++]; for(int i=head[u]; i; i=edge[i].next) { int v=edge[i].v; if(fa[u]!=v) { w[v]=edge[i].w; que[++ta]=v; fa[v]=u; de[v]=de[u]+1; } } } for(int j=ta; j; j--) { int u=que[j]; sz[u]=1; for(int i=head[u]; i; i=edge[i].next) { int v=edge[i].v; if(fa[u]!=v) { sz[u]+=sz[v]; if(sz[v]>sz[hs[u]])hs[u]=v; } } } top[1]=1; ch[1].push_back(1); for(int j=1; j<=ta; j++) { int u=que[j]; for(int i=head[u]; i; i=edge[i].next) { int v=edge[i].v; if(fa[u]!=v) { if(v==hs[u])top[v]=top[u]; else top[v]=v; ch[top[v]].push_back(v); } } } for(int u=1; u<=n; u++) { for(int i=0; i<ch[u].size(); i++) { int v=ch[u][i]; id[v]=++tot; s[tot]=s[tot-1]+w[v]; } } } void dfs1(int u) { sz[u]=1; for(int i=head[u]; i; i=edge[i].next) { int v=edge[i].v; if(v!=fa[u]) { fa[v]=u; de[v]=de[u]+1; w[v]=edge[i].w; dfs1(v); sz[u]+=sz[v]; if(sz[v]>sz[hs[u]])hs[u]=v; } } } void dfs2(int u) { id[u]=++tot; s[tot]=s[tot-1]+w[u]; if(hs[u]) { top[hs[u]]=top[u]; dfs2(hs[u]); } for(int i=head[u]; i; i=edge[i].next) { int v=edge[i].v; if(fa[u]!=v&&v!=hs[u]) { top[v]=v; dfs2(v); } } } int u1[maxn+10],u2[maxn+10],d[maxn+10]; int sum(int l,int r) { return s[r]-s[l-1]; } int dis(int u,int v) { if(u==v)return 0; if(top[u]==top[v]) { if(de[u]>de[v])swap(u,v); return sum(id[hs[u]],id[v]); } if(de[top[u]]>de[top[v]])swap(u,v); return sum(id[top[v]],id[v])+dis(u,fa[top[v]]); } //b为差分数组 int b[maxn+10]; void update(int l,int r) { b[l]++; b[r+1]--; } void modify(int u,int v) { if(top[v]==top[u]) { if(de[u]>de[v])swap(u,v); update(id[hs[u]],id[v]); } else { if(de[top[u]]>de[top[v]])swap(u,v); update(id[top[v]],id[v]); modify(u,fa[top[v]]); } } bool judge(int x) { clr(b,0); int cnt=0,m1=0; for(int i=1; i<=m; i++)if(d[i]>x) { cnt++; m1=max(m1,d[i]-x); modify(u1[i],u2[i]); } int tot=0,m2=0; for(int i=1; i<=n; i++) { tot+=b[i]; if(tot==cnt)m2=max(m2,sum(i,i)); } return m2>=m1; } int main() { scanf("%d%d",&n,&m); for(int i=1; i<n; i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); adde(a,b,c); adde(b,a,c); } bfs(); int l=0,r=0; for(int i=1; i<=m; i++) { scanf("%d%d",&u1[i],&u2[i]); d[i]=dis(u1[i],u2[i]); r=max(r,d[i]); } int ans; while(l<=r) { int mid=(l+r)/2; if(judge(mid)) { r=mid-1; ans=mid; } else l=mid+1; } printf("%d\n",ans); return 0; }
GG--未实现
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> using namespace std; const int N = 3e5 + 10; #define gc getchar() #define lson jd << 1 #define rson jd << 1 | 1 int head[N], deep[N], fa[N], topp[N], son[N], tree[N], siz[N], data[N], bef[N]; struct Node {int v, w, nxt;} G[N << 1]; struct Node_2 {int l, r, dis, Max, Maxfrom;} Ask[N]; struct Node_3 {int l, r, w, Max, Maxfrom;} T[N << 2]; int n, m, now, tim, ans; inline int read(){ int x = 0; char c = gc; while(c < ‘0‘ || c > ‘9‘) c = gc; while(c >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘, c = gc; return x; } inline void add(int u, int v, int w){ G[now].v = v; G[now].w = w; G[now].nxt = head[u]; head[u] = now ++; } void dfs_find_son(int u, int f_, int dep){ fa[u] = f_; deep[u] = dep; siz[u] = 1; for(int i = head[u]; ~ i; i = G[i].nxt){ int v = G[i].v; if(v != f_){ data[v] = G[i].w; dfs_find_son(v, u, dep + 1); siz[u] += siz[v]; if(siz[v] > siz[son[u]]) son[u] = v; } } } void dfs_to_un(int u, int tp){ topp[u] = tp; tree[u] = ++ tim; bef[tim] = u; if(!son[u]) return ; dfs_to_un(son[u], tp); for(int i = head[u]; ~ i; i = G[i].nxt){ int v = G[i].v; if(v != fa[u] && v != son[u]) dfs_to_un(v, v); } } void updata(int jd) { T[jd].w = T[lson].w + T[rson].w; T[jd].Max = max(T[lson].Max, T[rson].Max); } void build_tree(int l, int r, int jd){ T[jd].l = l; T[jd].r = r; if(l == r) { T[jd].w = data[bef[l]]; T[jd].Max = T[jd].w; return ; } int mid = (l + r) >> 1; build_tree(l, mid, lson); build_tree(mid + 1, r, rson); updata(jd); } void Sec_A(int l, int r, int jd, int x, int y){ if(x <= l && r <= y) {ans += T[jd].w; return ;} int mid = (l + r) >> 1; if(x <= mid) Sec_A(l, mid, lson, x, y); if(y > mid) Sec_A(mid + 1, r, rson, x, y); } int Sec_A_imp(int x, int y){ int tp1 = topp[x], tp2 = topp[y], answer = 0; while(tp1 != tp2){ if(deep[tp1] < deep[tp2]) swap(x, y), swap(tp1, tp2); ans = 0; Sec_A(1, n, 1, tree[tp1], tree[x]); answer += ans; x = fa[tp1]; tp1 = deep[x]; } if(x == y) return answer; ans = 0; if(deep[x] < deep[y]) swap(x, y); Sec_A(1, n, 1, tree[y] + 1, tree[x]); answer += ans; return answer; } void Poi_A(int l, int r, int jd, int x, int y){ if(x <= l && r <= y) { if(T[jd].Max > ans) {ans = T[jd].Max;} return ; } int mid = (l + r) >> 1; if(x <= mid) Poi_A(l, mid, lson, x, y); if(y > mid) Poi_A(mid + 1, r, rson, x, y); } int Poi_A_imp(int x, int y){ int tp1 = topp[x], tp2 = topp[y], answer = 0; while(tp1 != tp2){ if(deep[tp1] < deep[tp2]) swap(x, y), swap(tp1, tp2); ans = 0; Poi_A(1, n, 1, tree[tp1], tree[x]); if(ans > answer) {answer = ans;} x = fa[tp1]; tp1 = topp[x]; } if(x == y) return answer; ans = 0; if(deep[x] < deep[y]) swap(x, y); Poi_A(1, n, 1, tree[y] + 1, tree[x]); answer = max(answer, ans); return answer; } bool cmp(Node_2 a, Node_2 b){ return a.dis > b.dis; } void debug(){ for(int i = 1; i <= m; i ++) cout << Ask[i].dis << endl;cout << endl; for(int i = 1; i <= m; i ++) cout << Ask[i].Max << endl; exit(0); } int main() { freopen("gg.in", "r", stdin); n = read(); m = read(); for(int i = 1; i <= n; i ++) head[i] = -1; for(int i = 1; i <= n - 1; i ++) { int u = read(), v = read(), w = read(); add(u, v, w); add(v, u, w); } dfs_find_son(1, 0, 1); dfs_to_un(1, 1); build_tree(1, n, 1); for(int i = 1; i <= m; i ++){ Ask[i].l = read(); Ask[i].r = read(); Ask[i].dis = Sec_A_imp(Ask[i].l, Ask[i].r); } sort(Ask + 1, Ask + m + 1, cmp); int B = Ask[1].dis; int k = 1; while(Ask[k].dis == B){ Ask[k].Max = Poi_A_imp(Ask[k].l, Ask[k].r); k ++; } //debug(); for(int i = 1; i <= m; i ++){if(Ask[i].Max) Ask[i].dis -= Ask[i].Max;} int answer(0); for(int i = 1; i <= m; i ++) answer = max(answer, Ask[i].dis); cout << answer; return 0; } /* 6 3 1 2 3 1 6 4 3 1 7 4 3 6 3 5 5 3 6 2 5 4 5 */