题意:
给出一棵n个结点的树,边上有权值;
对于每个点求离它第k小的距离;
n<=50000;
题解:
正解似乎是树分治维护距离,然后二分答案啥的,时间复杂度O(nlog^3);
但是如果想不到树分治怎么办呢?那么就来写一个逗比做法吧!
考虑从一个点转移到另外一个点,这个转移过程对于一些点是增加这条边的权值,另一些是减少这条边的权值;
而投影到DFS序上,就是对于子树区间的加减修改;
从而将原题转化成区间修改+全局K小值的问题。。。
呵呵
于是我去膜了膜wyfcyx大爷,得到了一个污算法。。
反正不可做,那就分块吧(设每块的大小为B);
每个块内维护一个有序序列,查询时二分答案,然后统计小于当前mid的有多少数;
那么初始化就是n/B*BlogB=nlogB,每次查询都是log(ans)*n/B*logB;
每次修改整块的修改打标记,非整块的暴力修改,然后利用归并排序将序列重新排成有序;
这样每一次的修改就是n/B+B;
所以我们令B=√n*logn,时间复杂度为O(n*(log(ans)*√n+√n/logn+√n*logn)),大概就是O(n√nlogn)的啦。。。;
讲道理,我们这个√n比log^2n还是小一点的呢。。
然而实际上隐藏了一些常数。。不过对于极限数据,5s以内还是可以出解的;
bzoj 4317: Atm的树 双倍经验;
代码:
#include<math.h> #include<stdio.h> #include<string.h> #include<algorithm> #define N 51000 #define M 500000000 #define MEM 1000000 #define lson l,mid,no<<1 #define rson mid+1,r,no<<1|1 using namespace std; int next[N],to[N],val[N],head[N],ce; int L[N],R[N],tot; int n,k,B,cnt,ans[N]; int dis[N],cov[N]; struct node { int* t; int no; friend bool operator <(node a,node b) { return *a.t+cov[a.no]<*b.t+cov[b.no]; } }p[N]; void add(int x,int y,int v) { to[++ce]=y; next[ce]=head[x]; val[ce]=v; head[x]=ce; } void dfs(int x,int d) { L[x]=++tot; dis[L[x]]=d; for(int i=head[x];i;i=next[i]) dfs(to[i],d+val[i]); R[x]=tot; } void Build(int x) { int i,l=max(x*B,1),r=min((x+1)*B,n+1); for(i=l;i<r;i++) p[i].t=&dis[i],p[i].no=x; sort(p+l,p+r); } int calc(node t) { int i,ret=0,l,r; for(i=0;i<=cnt;i++) { l=max(i*B,1),r=min((i+1)*B,n+1); ret+=lower_bound(p+l,p+r,t)-p-l; } return ret; } int query() { int l,r,mid; node t; t.t=&mid,t.no=cnt+1; l=0,r=M; while(l<=r) { mid=l+r>>1; if(calc(t)+1<=k) l=mid+1; else r=mid-1; } return r; } void update(int l,int r,int v) { static node st[N][2]; int i,j,k,tl,tr,top[2]; for(i=0;i<l/B;i++) cov[i]+=v; for(i++;i<r/B;i++) cov[i]-=v; for(i=r/B+1;i<=cnt;i++) cov[i]+=v; if(l/B!=r/B) { tl=max(l/B*B,1),tr=min((l/B+1)*B,n+1); for(i=tl;i<tr;i++) { if(i<l) dis[i]+=v; else dis[i]-=v; } top[0]=top[1]=0; for(i=tl;i<tr;i++) { if(p[i].t>=&dis[l]) st[++top[0]][0]=p[i]; else st[++top[1]][1]=p[i]; } for(i=tl,j=1,k=1;i<tr;i++) { if(j<=top[0]&&k<=top[1]) p[i]=*st[j][0].t<*st[k][1].t?st[j++][0]:st[k++][1]; else p[i]=j<=top[0]?st[j++][0]:st[k++][1]; } tl=max(r/B*B,1),tr=min((r/B+1)*B,n+1); for(i=tl;i<tr;i++) { if(i<=r) dis[i]-=v; else dis[i]+=v; } top[0]=top[1]=0; for(i=tl;i<tr;i++) { if(p[i].t<=&dis[r]) st[++top[0]][0]=p[i]; else st[++top[1]][1]=p[i]; } for(i=tl,j=1,k=1;i<tr;i++) { if(j<=top[0]&&k<=top[1]) p[i]=*st[j][0].t<*st[k][1].t?st[j++][0]:st[k++][1]; else p[i]=j<=top[0]?st[j++][0]:st[k++][1]; } } else { tl=max(l/B*B,1),tr=min((l/B+1)*B,n+1); for(i=tl;i<tr;i++) { if(i<l||i>r) dis[i]+=v; else dis[i]-=v; } top[0]=top[1]=0; for(i=tl;i<tr;i++) { if(p[i].t<&dis[l]||p[i].t>&dis[r]) st[++top[0]][0]=p[i]; else st[++top[1]][1]=p[i]; } for(i=tl,j=1,k=1;i<tr;i++) { if(j<=top[0]&&k<=top[1]) p[i]=*st[j][0].t<*st[k][1].t?st[j++][0]:st[k++][1]; else p[i]=j<=top[0]?st[j++][0]:st[k++][1]; } } } void slove(int x) { ans[x]=query(); for(int i=head[x];i;i=next[i]) { update(L[to[i]],R[to[i]],val[i]); slove(to[i]); update(L[to[i]],R[to[i]],-val[i]); } } int main() { int i,x,y,v; scanf("%d%d",&n,&k); k++; B=(int)sqrt(n)*log2(n); cnt=n/B; for(i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&v); add(x,y,v); } dfs(1,0); for(i=0;i<=cnt;i++) Build(i); slove(1); for(i=1;i<=n;i++) printf("%d\n",ans[i]); return 0; }
时间: 2024-12-29 12:39:16