
P3714 [BJOI2017]树的难题 点分治+线段树合并
发布日期:2021-05-09 04:44:50
浏览次数:10
分类:博客文章
本文共 3254 字,大约阅读时间需要 10 分钟。
题目描述
分析
路径问题考虑点分治
对于一个分治中心,我们可以很容易地得到从它开始的一条路径的价值和长度
问题就是如何将不同的路径合并
很显然,对于同一个子树中的所有路径,它们起始的颜色是相同的
因此我们可以将一个节点的所有子结点按照颜色排序
这个可以在建图之前处理好
然后开两个权值线段树,以路径的长度作为下标
一棵存储与当前节点起始颜色相同的所有路径,另一棵存储起始颜色不同的所有路径
对于长度为 \(i\) 的路径,我们直接查询区间 \([l-i,r-i]\) 的最大值即可
当节点的颜色改变时,把相同的那一堆合并到另一堆即可
时间复杂度 \(nlog^2n\)
代码
#include#include #include #include #include #define rg registerinline int read(){ rg int x=0,fh=1; rg char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') fh=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*fh;}const int maxn=4e5+5;int h[maxn],tot=1,n,m,lef,rig,val[maxn];struct asd{ int to,nxt,val;}b[maxn];void ad(rg int aa,rg int bb,rg int cc){ b[tot].to=bb; b[tot].nxt=h[aa]; b[tot].val=cc; h[aa]=tot++;}int siz[maxn],maxsiz[maxn],rt,totsiz;bool vis[maxn];void getroot(rg int now,rg int lat){ siz[now]=1,maxsiz[now]=0; for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==lat || vis[u]) continue; getroot(u,now); siz[now]+=siz[u]; maxsiz[now]=std::max(maxsiz[now],siz[u]); } maxsiz[now]=std::max(maxsiz[now],totsiz-siz[now]); if(maxsiz[now] >1; if(wz<=mids) tr[da].lch=xg(tr[da].lch,l,mids,wz,val); else tr[da].rch=xg(tr[da].rch,mids+1,r,wz,val); push_up(da); return da;}int bing(rg int aa,rg int bb,rg int l,rg int r){ if(!aa || !bb) return aa+bb; if(l==r){ tr[aa].val=std::max(tr[aa].val,tr[bb].val); tr[bb].val=-0x3f3f3f3f; return aa; } rg int mids=(l+r)>>1; tr[aa].lch=bing(tr[aa].lch,tr[bb].lch,l,mids); tr[aa].rch=bing(tr[aa].rch,tr[bb].rch,mids+1,r); push_up(aa); return aa;}int cx(rg int da,rg int l,rg int r,rg int nl,rg int nr){ if(!da || l>r) return -0x3f3f3f3f; if(l>=nl && r<=nr) return tr[da].val; rg int mids=(l+r)>>1,nans=-0x3f3f3f3f; if(nl<=mids) nans=std::max(nans,cx(tr[da].lch,l,mids,nl,nr)); if(nr>mids) nans=std::max(nans,cx(tr[da].rch,mids+1,r,nl,nr)); return nans;}struct jie{ int val,dep; jie(){} jie(rg int aa,rg int bb){ val=aa,dep=bb; }}sta[maxn];bool cmp(rg jie aa,rg jie bb){ return aa.val>bb.val;}std::vector g[maxn];void dfs(rg int now,rg int lat,rg int nval,rg int ndep,rg int latcol){ if(ndep>rig) return; sta[++tp]=jie(nval,ndep); for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==lat || vis[u]) continue; dfs(u,now,(latcol==b[i].val)?nval:nval+val[b[i].val],ndep+1,b[i].val); }}void solve(rg int now){ vis[now]=1; rt1=rt2=cnt=0; rg int latcol=0,jud=0; for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(!vis[u]){ tp=jud=0; dfs(u,now,val[b[i].val],1,b[i].val); if(b[i].val==latcol) jud=1; else { rt1=bing(rt1,rt2,1,n); rt2=0; } for(rg int j=1;j<=tp;j++){ if(jud) ans=std::max(ans,cx(rt2,1,n,std::max(1,lef-sta[j].dep),rig-sta[j].dep)+sta[j].val-val[latcol]); ans=std::max(ans,cx(rt1,1,n,std::max(1,lef-sta[j].dep),rig-sta[j].dep)+sta[j].val); if(sta[j].dep>=lef && sta[j].dep<=rig) ans=std::max(ans,sta[j].val); } for(rg int j=1;j<=tp;j++) rt2=xg(rt2,1,n,sta[j].dep,sta[j].val); latcol=b[i].val; } } for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(!vis[u]){ totsiz=siz[u],rt=0; getroot(u,now); solve(rt); } }}int main(){ memset(h,-1,sizeof(h)); n=read(),m=read(),lef=read(),rig=read(); for(rg int i=1;i<=m;i++) val[i]=read(); rg int aa,bb,cc; for(rg int i=1;i
发表评论
最新留言
路过,博主的博客真漂亮。。
[***.116.15.85]2025年04月06日 13时11分19秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
C#中Dispose和Close的区别!
2019-03-06
如何让服务在流量暴增的情况下保持稳定输出
2019-03-06
一个20年技术老兵的 2020 年度技术总结
2019-03-06
一例完整的websocket实现群聊demo
2019-03-06
SQLSERVER数据库死锁与优化杂谈
2019-03-06
【Net】ABP框架学习之它并不那么好用
2019-03-06
Git 笔记
2019-03-06
Harbor 批量清理历史镜像
2019-03-06
使用Azure Functions玩转Serverless
2019-03-06
.NET Core 基于Websocket的在线聊天室
2019-03-06
使用MySQL Shell创建MGR
2019-03-06
win10新版wsl2使用指南
2019-03-06
spring-boot 使用hibernate validation对参数进行优雅的校验
2019-03-06
关于我
2019-03-06
数据结构实验之栈四:后缀式求值
2019-03-06
图结构练习——最小生成树(prim算法(普里姆))
2019-03-06
sdut 2498【aoe 网上的关键路径】
2019-03-06
【PHP自定义显示系统级别的致命错误和用户级别的错误】
2019-03-06
【JAVA多线程中使用的方法】
2019-03-06
【JAVA网络流之URL】
2019-03-06