LibreOJ 2179 「BJOI2017」树的难题 发表于 2020.07.30 | 分类于 题解 | 19 显而易见地,点分治然后暴力维护两棵线段树(颜色相同 / 不同)算贡献,算完之后合并这两棵线段树再看下一种颜色( 代码: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237#include <cstdio>#include <vector>#include <algorithm>using namespace std;const int N = 2e5;int n,m,l,r;int a[N + 5],v[N + 5];int to[(N << 1) + 5],pre[(N << 1) + 5],val[(N << 1) + 5],first[N + 5];inline void add(int u,int v,int w){ static int tot = 0; to[++tot] = v,val[tot] = w,pre[tot] = first[u],first[u] = tot;}namespace SEG{ struct node { int max; int ls,rs; } seg[(N << 3) + 10]; int rt[N + 5]; int init() { seg[0].max = -2e9; return 0; } int Init = init(),tot; void insert(int x,int k,int &p,int tl,int tr) { !p && (seg[p = ++tot].max = -2e9,seg[p].ls = seg[p].rs = 0),seg[p].max = max(seg[p].max,k); if(tl == tr) return ; int mid = tl + tr >> 1; x <= mid ? insert(x,k,seg[p].ls,tl,mid) : insert(x,k,seg[p].rs,mid + 1,tr); } int query(int l,int r,int p,int tl,int tr) { if(!p || (l <= tl && tr <= r)) return seg[p].max; int mid = tl + tr >> 1; int ret = -2e9; l <= mid && (ret = max(ret,query(l,r,seg[p].ls,tl,mid))); r > mid && (ret = max(ret,query(l,r,seg[p].rs,mid + 1,tr))); return ret; } int merge(int p,int q) { if(!p || !q) return p | q; seg[p].max = max(seg[p].max,seg[q].max), seg[p].ls = merge(seg[p].ls,seg[q].ls),seg[p].rs = merge(seg[p].rs,seg[q].rs); return p; }}namespace LIS{ int pre[N + 5],first[N + 5]; inline void add(int p,int v) { pre[p] = first[v],first[v] = p; }}int vis[N + 5],sum,sz[N + 5],max_part[N + 5],cur[N + 5],rt;int done[N + 5];int dis[N + 5],dep[N + 5],fa[N + 5];int col[N + 5],len;int ans;void get_rt(int p){ done[p] = fa[p] = 0; for(int flag;;) { flag = 0; if(!done[p]) sz[p] = 1,max_part[p] = 0,cur[p] = first[p],done[p] = 1; for(register int i = cur[p];i;i = pre[i]) { cur[p] = pre[i]; if((to[i] ^ fa[p]) && !vis[to[i]]) { done[to[i]] = 0,fa[to[i]] = p,p = to[i],flag = 1; break; } } if(!flag) { max_part[p] = max(max_part[p],sum - sz[p]); max_part[p] < max_part[rt] && (rt = p); if(fa[p]) { sz[fa[p]] += sz[p],max_part[fa[p]] = max(max_part[fa[p]],sz[p]); p = fa[p]; } else break; } } /*sz[p] = 1,max_part[p] = 0; for(register int i = first[p];i;i = pre[i]) if((to[i] ^ fa) && !vis[to[i]]) get_rt(to[i],p),sz[p] += sz[to[i]],max_part[p] = max(max_part[p],sz[to[i]]); max_part[p] = max(max_part[p],sum - sz[p]); max_part[p] < max_part[rt] && (rt = p);*/}void get_dis(int p){ done[p] = fa[p] = 0; for(int flag;;) { flag = 0; if(!done[p]) cur[p] = first[p],done[p] = 1; for(register int i = cur[p];i;i = pre[i]) { cur[p] = pre[i]; if((to[i] ^ fa[p]) && !vis[to[i]]) { done[to[i]] = 0,fa[to[i]] = p,dep[to[i]] = dep[p] + 1,v[to[i]] = val[i],dis[to[i]] = dis[p] + (v[p] != v[to[i]]) * a[v[to[i]]],p = to[i],flag = 1; break; } } if(!flag) if(fa[p]) p = fa[p]; else break; } /*for(register int i = first[p];i;i = pre[i]) if((to[i] ^ fa) && !vis[to[i]]) dep[to[i]] = dep[p] + 1,v[to[i]] = val[i],dis[to[i]] = dis[p] + (v[p] != v[to[i]]) * a[v[to[i]]],get_dis(to[i],p);*/}void calc(int p,int c){ done[p] = fa[p] = 0; for(int flag;;) { flag = 0; if(!done[p]) { cur[p] = first[p],done[p] = 1; if(dep[p] >= l && dep[p] <= r) ans = max(ans,dis[p]); int temp = SEG::query(max(l - dep[p],1),r - dep[p],SEG::rt[0],1,n); if(temp > -2e9) ans = max(ans,temp + dis[p]); temp = SEG::query(max(l - dep[p],1),r - dep[p],SEG::rt[c],1,n); if(temp > -2e9) ans = max(ans,temp + dis[p] - a[c]); } for(register int i = cur[p];i;i = pre[i]) { cur[p] = pre[i]; if((to[i] ^ fa[p]) && !vis[to[i]] && dep[to[i]] <= r) { done[to[i]] = 0,fa[to[i]] = p,p = to[i],flag = 1; break; } } if(!flag) if(fa[p]) p = fa[p]; else break; } /*if(dep[p] >= l && dep[p] <= r) ans = max(ans,dis[p]); if(dep[p] > r) return ; for(register int i = first[p];i;i = pre[i]) if((to[i] ^ fa) && !vis[to[i]]) calc(to[i],p,c);*/}void insert(int p,int c){ done[p] = fa[p] = 0; for(int flag;;) { flag = 0; if(!done[p]) { cur[p] = first[p],done[p] = 1; SEG::insert(dep[p],dis[p],SEG::rt[c],1,n); } for(register int i = cur[p];i;i = pre[i]) { cur[p] = pre[i]; if((to[i] ^ fa[p]) && !vis[to[i]] && dep[to[i]] <= r) { done[to[i]] = 0,fa[to[i]] = p,p = to[i],flag = 1; break; } } if(!flag) if(fa[p]) p = fa[p]; else break; } /*if(dep[p] > r) return ; SEG::insert(dep[p],dis[p],SEG::rt[c],1,n); for(register int i = first[p];i;i = pre[i]) if((to[i] ^ fa) && !vis[to[i]]) insert(to[i],p,c);*/}void solve(int p){ vis[p] = 1,dep[p] = dis[p] = v[p] = 0,get_dis(p),len = 0; for(register int i = first[p];i;i = pre[i]) if(!vis[to[i]]) LIS::add(to[i],v[to[i]]),col[++len] = v[to[i]]; sort(col + 1,col + len + 1),len = unique(col + 1,col + len + 1) - col - 1; for(register int ci = 1,c;ci <= len;++ci) { c = col[ci]; for(register int i = LIS::first[c];i;i = LIS::pre[i]) calc(i,c),insert(i,c); SEG::rt[0] = SEG::merge(SEG::rt[0],SEG::rt[c]), LIS::first[c] = SEG::rt[c] = 0; } SEG::tot = SEG::rt[0] = 0; for(register int i = first[p];i;i = pre[i]) if(!vis[to[i]]) rt = 0,sum = sz[to[i]],fa[to[i]] = p,get_rt(to[i]),solve(rt);}int main(){ max_part[0] = 0x3f3f3f3f,ans = -2e9; scanf("%d%d%d%d",&n,&m,&l,&r); for(register int i = 1;i <= m;++i) scanf("%d",a + i); int u,v,w; for(register int i = 2;i <= n;++i) scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w); vis[0] = 1,rt = 0,sum = n,get_rt(1),solve(rt); printf("%d\n",ans);} 本文作者: Alpha1022 本文链接: https://www.alpha1022.me/articles/loj-2179.htm 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明出处!