[2017集训队作业自选题#117]Monkey and Tree
来源:互联网 发布:cnc编程兼职群 编辑:程序博客网 时间:2024/06/06 07:18
题目大意
一颗边权树,给你若干点对(ai,bi)。
找到两对点对i和j,使得dis(ai,aj)+dis(bi,bj)最大。
做法
先建立点分树。
然后进行点分,对于当前分治中心x,讨论最终点对中两个a路径是否过x。
不过x,递归处理。
过x,求出当前分治联通块每个点到x的距离,然后接下来按一个一个子树处理(一起询问,再一起插入,来保证不在同一个子树),我们把b插入到点分树中,对于点分树一个分治中心y,处理出dis(a,x)+dis(b,y)的最大值、最大值来自哪个子树以及不来自同一个子树的次大值,即可完成询问。
#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;const int maxn=100000+10;const ll inf=10000000000000000;int h[maxn],go[maxn*2],dis[maxn*2],nxt[maxn*2],a[maxn];int ask[maxn][2],h2[maxn],g2[maxn],n2[maxn],size[maxn];int belong[maxn][25],son[maxn][25],mxf[maxn];int sta[maxn];ll d[maxn],dep[maxn][25],mx[maxn],se[maxn];bool bz[maxn],pd[maxn];int i,j,k,l,t,n,m,top,tot,cnt;ll ans;int read(){ int x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9'){ if (ch=='-') f=-1; ch=getchar(); } while (ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*f;}void add(int x,int y,int z){ go[++tot]=y; dis[tot]=z; nxt[tot]=h[x]; h[x]=tot;}void add2(int x,int y){ g2[++tot]=y; n2[tot]=h2[x]; h2[x]=tot;}void travel(int x,int y){ a[++top]=x; size[x]=1; int t=h[x]; while (t){ if (!bz[go[t]]&&go[t]!=y){ travel(go[t],x); size[x]+=size[go[t]]; } t=nxt[t]; }}void dg(int x,int y,int d,int c){ son[x][d]=c; int t=h[x]; while (t){ if (!bz[go[t]]&&go[t]!=y){ dep[go[t]][d]=dep[x][d]+(ll)dis[t]; dg(go[t],x,d,c); } t=nxt[t]; }}void build(int x,int y){ top=0; travel(x,0); int i,t,j=x,k=0; while (1){ t=h[j]; while (t){ if (!bz[go[t]]&&go[t]!=k&&size[go[t]]>top/2){ k=j; j=go[t]; break; } t=nxt[t]; } if (!t) break; } fo(i,1,top) belong[a[i]][y]=j; t=h[j]; while (t){ if (!bz[go[t]]){ dep[go[t]][y]=dis[t]; dg(go[t],j,y,go[t]); } t=nxt[t]; } son[j][y]=j; bz[j]=1; t=h[j]; while (t){ if (!bz[go[t]]) build(go[t],y+1); t=nxt[t]; }}void change(int x,ll v){ int j; int y; ll w; fo(j,0,25){ y=belong[x][j]; if (!pd[y]){ pd[y]=1; sta[++cnt]=y; } w=v+dep[x][j]; if (mxf[y]==son[x][j]) mx[y]=max(mx[y],w); else if (w>=mx[y]){ se[y]=mx[y]; mx[y]=w; mxf[y]=son[x][j]; } else if (w>=se[y]) se[y]=w; if (x==y) break; }}void query(int x,ll v){ int j; int y; ll w; fo(j,0,25){ y=belong[x][j]; if (mx[y]==-inf) return; w=v+dep[x][j]; if (mxf[y]==son[x][j]) ans=max(ans,w+se[y]); else ans=max(ans,w+mx[y]); if (x==y) break; }}void cx(int x,int y,int d){ int t=h2[x]; while (t){ query(g2[t],dep[x][d]); t=n2[t]; } t=h[x]; while (t){ if (!bz[go[t]]&&go[t]!=y) cx(go[t],x,d); t=nxt[t]; }}void cr(int x,int y,int d){ int t=h2[x]; while (t){ change(g2[t],dep[x][d]); t=n2[t]; } t=h[x]; while (t){ if (!bz[go[t]]&&go[t]!=y) cr(go[t],x,d); t=nxt[t]; }}void solve(int x,int y){ int j=belong[x][y]; cnt=0; int t=h2[j]; while (t){ query(g2[t],0); change(g2[t],0); t=n2[t]; } t=h[j]; while (t){ if (!bz[go[t]]){ cx(go[t],j,y); cr(go[t],j,y); } t=nxt[t]; } int i; fo(i,1,cnt){ pd[sta[i]]=0; mx[sta[i]]=se[sta[i]]=-inf; mxf[sta[i]]=0; } bz[j]=1; t=h[j]; while (t){ if (!bz[go[t]]) solve(go[t],y+1); t=nxt[t]; }}int main(){ n=read();m=read(); fo(i,1,n-1){ j=read();k=read();l=read(); add(j,k,l);add(k,j,l); } tot=0; fo(i,1,m){ ask[i][0]=read();ask[i][1]=read(); add2(ask[i][0],ask[i][1]); } build(1,0); fo(i,1,n) mx[i]=se[i]=-inf; fo(i,1,n) bz[i]=0; solve(1,0); printf("%lld\n",ans);}
阅读全文
0 0
- [2017集训队作业自选题#117]Monkey and Tree
- [2017集训队作业自选题#154]简单数据结构题
- [2017集训队作业自选题#153]Comb Avoiding Trees
- [2017集训队作业自选题#115]Replace All
- [2017集训队作业自选题#119]众数MAX
- [2017集训队作业自选题#134]Counting Divisors (square)
- [2017集训队作业自选题#148]Simple Summation Problem
- [2017集训队作业自选题#107]An unavoidable detour for home
- 集训队作业
- 我的集训队作业
- 【集训队作业】MONOPLOY
- 【集训队作业】TREECNT2
- 【集训队作业】DGCD
- 【集训队作业】XRQRS
- 【集训队作业】LYRC
- 【集训队作业】COUNTARI
- 2015年集训队作业
- 【AtCoder arc072_f/集训队作业】 Dam
- 从决策树到GBDT
- 什么是数据分析/数据科学?
- Android studio 3.0导入工程遇到的错误
- DPDK Pktgen+Docker搭建VNF环境及验证
- Java交流共享群
- [2017集训队作业自选题#117]Monkey and Tree
- FragmentPagerAdapter与FragmentStatePagerAdapter区别
- aop面向切面编程(aspectJweaver)
- Superset 二次开发
- 01:Hello, World!
- behavior3editor生成过程(备忘)
- Redis4.0新特性(三)-PSYNC2
- css js 限制td显示数量
- quick-cocos2d-x 脚本和资源加密