把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

BZOJ #3784. 树上的路径

题面传送门
首先显然有一个三只log的做法,就是先二分,然后点分找大于这个值的路径,直接爆炸。
考虑有什么更优的方法,我们将点分治的顺序跑出来,然后发现一个点计算答案的区间一定是一段区间。
然后我们像超级钢琴那样就好了。
区间最大值的话如果是线段树是\(O(n+m)logn\),st表是\(O(nlog^2n+mlogn)\),关键这两个跑得一样快。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define lb long db
#define N 200000
#define K 20
#define mod 998244353
#define Mod 998244352
#define eps (1e-4)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Pc(x) putchar(x) 
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
using namespace std;
int n,m,k,d[N+5<<5],siz[N+5],Maxn[N+5],vis[N+5],F[N+5],dfn[N+5<<5],dh,l[N+5<<5],r[N+5<<5],root,G[N+5<<7],pus,p,x,y,z;
struct yyy{int to,w,z;};
struct ljb{int head,h[N+5];yyy f[N+5<<1];I void add(int x,int y,int z){f[++head]=(yyy){y,z,h[x]};h[x]=head;}}s;
I int Getsiz(int x,int last){int Ans=1;yyy tmp;for(int i=s.h[x];i;i=tmp.z) tmp=s.f[i],tmp.to^last&&!vis[tmp.to]&&(Ans+=Getsiz(tmp.to,x));return Ans;}
I void dfs1(int x,int last,int sum){F[x]=1;Maxn[x]=0;yyy tmp;for(int i=s.h[x];i;i=tmp.z)tmp=s.f[i],tmp.to^last&&!vis[tmp.to]&&(dfs1(tmp.to,x,sum),F[x]+=F[tmp.to],Maxn[x]=max(Maxn[x],F[tmp.to]));Maxn[x]=max(Maxn[x],sum-F[x]);Maxn[x]<=sum/2&&(root=x);}
I void dfs2(int x,int last,int ls,int rs){int now;dfn[now=++dh]=x;l[dh]=ls;r[dh]=rs;yyy tmp;for(int i=s.h[x];i;i=tmp.z) tmp=s.f[i],!vis[tmp.to]&&tmp.to^last&&(d[dh+1]=d[now]+tmp.w,dfs2(tmp.to,x,ls,rs),0);}
I void dfs(int x){
	yyy tmp;root=x;dfs1(x,0,Getsiz(x,0));x=root;vis[x]=1;dfn[++dh]=x;l[dh]=r[dh]=dh;int i,lastdh=dh;for(i=s.h[x];i;i=tmp.z) tmp=s.f[i],!vis[tmp.to]&&(d[dh+1]=tmp.w,dfs2(tmp.to,x,lastdh,dh),0);for(i=s.h[x];i;i=tmp.z) tmp=s.f[i],!vis[tmp.to]&&(dfs(tmp.to),0);
}
struct Ques{int w,id,l,r,p;bool operator <(const Ques &B)const{return w<B.w;};}now;priority_queue<Ques> Q;I int Up(int x,int y){return d[x]>d[y]?x:y;}
I void build(int l=1,int r=dh,int now=1){if(l==r) return (void)(G[now]=l);int m=l+r>>1;build(l,m,now<<1);build(m+1,r,now<<1|1);G[now]=Up(G[now<<1],G[now<<1|1]);}
I int Query(int x,int y,int l=1,int r=dh,int now=1){if(x<=l&&r<=y) return G[now];int m=l+r>>1,Ans=0;x<=m&&(Ans=Up(Ans,Query(x,y,l,m,now<<1)));y>m&&(Ans=Up(Ans,Query(x,y,m+1,r,now<<1|1)));return Ans;}
int main(){
//	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	re int i;scanf("%d%d",&n,&m);for(i=1;i<n;i++) scanf("%d%d%d",&x,&y,&z),s.add(x,y,z),s.add(y,x,z);dfs(1);build();for(i=1;i<=dh;i++) pus=Query(l[i],r[i]),Q.push((Ques){d[pus]+d[i],i,l[i],r[i],pus});
	while(m--){now=Q.top();Q.pop();printf("%d\n",now.w);now.p^now.l&&(pus=Query(now.l,now.p-1),Q.push((Ques){d[pus]+d[now.id],now.id,now.l,now.p-1,pus}),0);now.p^now.r&&(pus=Query(now.p+1,now.r),Q.push((Ques){d[pus]+d[now.id],now.id,now.p+1,now.r,pus}),0);}
}
posted @ 2021-08-17 18:00  275307894a  阅读(40)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end