JZOJ 5898. 【NOIP2018模拟10.6】距离统计
生活随笔
收集整理的這篇文章主要介紹了
JZOJ 5898. 【NOIP2018模拟10.6】距离统计
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Description
Input
Output
Sample Input
5 3
1 2 3
1 3 1
2 4 4
2 5 2
1 2
3 3
5 1
Sample Output
3
6
2
Data Constraint
Solution
-
這題用到點分樹,即點分治時重心(前面的連向后面的)建成的樹。
-
在每個點上記錄一個數組 fff,保存該點子樹里的點到其距離(原樹,包括自己),并排好序。
-
詢問要二分答案 kkk ,并判斷有多少個點的距離 ≤k\leq k≤k 即可。
-
那么詢問時從該點開始往點分樹的父親上走,每次加上符合的個數(在數組 fff 里二分即可)。
-
但是這樣會算重,即從點分樹父親那兒走到自己的答案可能算重了,我們需要減去一些。
-
于是再開一個數組 ggg ,記錄一個點子樹里(原樹,包括自己)到其點分樹父親的距離。
-
在排好序的數組 ggg 里二分算重的個數并減去即可。
-
詢問時二分答案、在點分樹上往父親跳、在數組里二分計算的復雜度均為 O(logn)O(log\ n)O(log?n) 。
-
總時間復雜度為 O(nlog?3n)O(n\log^3n)O(nlog3n) 。
Code
#include<cstdio> #include<algorithm> #include<cmath> #include<vector> #include<cctype> using namespace std; const int N=5e4+5; int n,tot,node,mx,dep,dis,siz; int first[N],nex[N<<1],en[N<<1],w[N<<1]; int first1[N],nex1[N],en1[N]; int fa[N],f[N],size[N],h[N][16],len[N][16],deep[N],dp[N],pre[N][20]; bool bz[N]; vector<int>g[N],d[N]; inline int read() {int X=0,w=0; char ch=0;while(!isdigit(ch)) w|=ch=='-',ch=getchar();while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();return w?-X:X; } void write(int x) {if(x>9) write(x/10);putchar(x%10+'0'); } inline int max(int x,int y) {return x>y?x:y; } inline void insert(int x,int y,int z) {nex[++tot]=first[x];first[x]=tot;en[tot]=y;w[tot]=z; } inline void insert1(int x,int y) {nex1[++tot]=first1[x];first1[x]=tot;en1[tot]=y; } void find(int x,int y,int z) {size[x]=1;f[x]=0;for(int i=first[x];i;i=nex[i])if(en[i]^y && !bz[en[i]]){find(en[i],x,z+w[i]);size[x]+=size[en[i]];f[x]=max(f[x],size[en[i]]);}f[x]=max(f[x],siz-size[x]);if(f[x]<mx) mx=f[node=x],dep=z; } void down(int x,int y,int rt,int z) {g[rt].push_back(z);for(int i=first[x];i;i=nex[i])if(en[i]^y && !bz[en[i]]) down(en[i],x,rt,z+w[i]); } void dfs(int x,int y) {bz[x]=true;if(fa[x]=y) insert1(y,x);int siz1=siz;for(int i=first[x];i;i=nex[i])if(!bz[en[i]]){if(size[x]<size[en[i]]) siz=siz1-size[x]; else siz=size[en[i]];mx=siz;find(en[i],x,w[i]);down(node,0,node,0);dfs(node,x);} } void get(int x,int y,int z) {if(z>dis) dis=z,node=x;for(int i=first[x];i;i=nex[i])if(en[i]^y){if(en[i]>1 && !h[en[i]][0]){h[en[i]][0]=x;len[en[i]][0]=w[i];deep[en[i]]=deep[x]+1;}get(en[i],x,z+w[i]);} } inline int calc(int x,int y) {if(deep[x]<deep[y]) swap(x,y);int s=0;for(int i=log2(deep[x]);i>=0;i--)if(deep[h[x][i]]>=deep[y]){s+=len[x][i];x=h[x][i];}if(x==y) return s;for(int i=log2(deep[x]);i>=0;i--)if(h[x][i]^h[y][i]){s+=len[x][i]+len[y][i];x=h[x][i];y=h[y][i];}s+=len[x][0]+len[y][0];return s; } void dg(int x) {dp[x]=dp[fa[x]]+1;for(int y=fa[x],l=x;y;l=y,y=fa[y]){int z=calc(x,y);pre[x][dp[y]]=z;if(l) d[l].push_back(z);}for(int i=first1[x];i;i=nex1[i])if(en1[i]^fa[x]) dg(en1[i]); } int main() {freopen("tree.in","r",stdin);freopen("tree.out","w",stdout);n=read();int m=read();for(int i=1;i<n;i++){int x=read(),y=read(),z=read();insert(x,y,z);insert(y,x,z);}get(deep[1]=1,0,0);get(node,0,0);for(int j=1;j<16;j++)for(int i=1;i<=n;i++){h[i][j]=h[h[i][j-1]][j-1];len[i][j]=len[i][j-1]+len[h[i][j-1]][j-1];}tot=0;mx=siz=n;find(1,0,0);down(node,0,node,0);dfs(node,0);for(int i=1;i<=n;i++)if(!fa[i]){node=i;break;}dg(node);for(int i=1;i<=n;i++) g[i].push_back(dis);for(int i=1;i<=n;i++) sort(g[i].begin(),g[i].end());for(int i=1;i<=n;i++) d[i].push_back(dis);for(int i=1;i<=n;i++) sort(d[i].begin(),d[i].end());/*for(int j=1;j<=n;j++,putchar('\n'))for(int i=0;i<(int)g[j].size();i++) printf("%d ",g[j][i]);*/while(m--){int u=read(),k=read()+1;int l=1,r=dis,ans=0;while(l<=r){int mid=l+r>>1;int sum=upper_bound(g[u].begin(),g[u].end(),mid)-g[u].begin();for(int x=u;x^node;x=fa[x]){int lim=pre[u][dp[fa[x]]];if(lim>mid) continue;sum+=upper_bound(g[fa[x]].begin(),g[fa[x]].end(),mid-lim)-g[fa[x]].begin();sum-=upper_bound(d[x].begin(),d[x].end(),mid-lim)-d[x].begin();}if(sum>=k){ans=mid;r=mid-1;}else l=mid+1;}write(ans),putchar('\n');}return 0; }總結
以上是生活随笔為你收集整理的JZOJ 5898. 【NOIP2018模拟10.6】距离统计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JZOJ 5878. 【NOIP2018
- 下一篇: JZOJ 5906. 【NOIP2018