1. 程式人生 > >[JZOJ5898]【NOIP2018模擬10.6】距離統計

[JZOJ5898]【NOIP2018模擬10.6】距離統計

Description

給定一棵n個節點的帶邊權樹,m組詢問,每次詢問兩個數u,k,求出u本身外到u的第k小距離(相等距離會算多次)
n,m<=50000

Solution

這絕對假NOIP。。

首先肯定是二分答案,將問題轉化為判定性問題,求有多少個距離小於mid的

把點分治樹構出來,對於每個節點弄出以它為分治中心(點分樹上以它為根的子樹)的節點到它的距離,排好序。

查詢某一個點的某一個距離,只需要從這個點開始向點分樹上父親跳,跳到一個父親就二分查詢個數。

這樣有可能會算重,跳上來的那個子樹應該被減掉。

只需要在點分樹上記它的子樹中所有節點到它父親的距離,跳的時候在這個陣列中一樣二分,減掉即可。

複雜度 O ( n log 3 n )

O(n\log^3 n ) (簡直喪心病狂)

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <cstdlib>
#include <set>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 50005 #define M 30*N using namespace std; int fs[N],nt[2*N],dt[2*N],n,m,q,pr[2*N],n1,sz[N],a1[N][2],d[M],dis[21][N],mi,mw,fa[N],dep[N],d2[M]; bool bz[N]; void link(int x,int y,int z) { nt[++m]=fs[x]; dt[fs[x]=m]=y; pr[m]=z; } void dfs(int k,int fa,int num) { sz[k]=1; int mx=0; for(int i=fs[k];i;i=nt[i]) { int p=dt[i]; if(p!=fa&&!bz[p]) dfs(p,k,num),sz[k]+=sz[p],mx=max(mx,sz[p]); } if(max(mx,num-sz[k])<mi) mi=max(mx,num-sz[k]),mw=k; } void make(int k,int fa,int st) { d[++d[0]]=dis[dep[st]][k]; d2[d[0]]=dis[dep[st]-1][k]; for(int i=fs[k];i;i=nt[i]) { int p=dt[i]; if(p!=fa&&!bz[p]) { dis[dep[st]][p]=dis[dep[st]][k]+pr[i]; make(p,k,st); } } } void doit(int k,int num) { dfs(k,0,num); dis[dep[k]][k]=0; a1[k][0]=d[0]+1; make(k,0,k); bz[k]=1; a1[k][1]=d[0]; sort(d+a1[k][0],d+a1[k][1]+1); sort(d2+a1[k][0],d2+a1[k][1]+1); for(int i=fs[k];i;i=nt[i]) { int p=dt[i]; if(!bz[p]) { mi=sz[p]+1; dfs(p,k,sz[p]); fa[mw]=k; dep[mw]=dep[k]+1; doit(mw,sz[p]); } } } int ct(int x,int lim) { int s=-1,st=x; int p=upper_bound(d+a1[x][0],d+a1[x][1]+1,lim)-d,q; s+=p-a1[x][0]; int k=x; x=fa[x]; while(x) { p=upper_bound(d+a1[x][0],d+a1[x][1]+1,lim-dis[dep[x]][st])-d; q=upper_bound(d2+a1[k][0],d2+a1[k][1]+1,lim-dis[dep[x]][st])-d2; s+=(p-a1[x][0])-(q-a1[k][0]); k=x; x=fa[x]; } return s; } int main() { freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); cin>>n>>q; int smx=0; fo(i,1,n-1) { int x,y,z; scanf("%d%d%d",&x,&y,&z); link(x,y,z),link(y,x,z); smx+=z; } mi=n+1; dfs(1,0,n); dep[mw]=1; doit(mw,n); fo(i,1,q) { int x,w; scanf("%d%d",&x,&w); int l=1,r=smx; while(l+1<r) { int mid=(l+r)>>1; if(ct(x,mid)>=w) r=mid; else l=mid; } if(ct(x,l)>=w) r=l; printf("%d\n",r); } }