BZOJ4317: Atm的树
Description
Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree……
于是,一天晚上他梦到自己被关在了一个有根树中,每条路径都有边权,一个神秘的声音告诉他,每个点到其他的点有一个距离(什么是距离不用说吧),他需要对于每个点回答:从这个点出发的第k小距离是多少;
如果atm不能回答出来,那么明天4019的闹钟将不会响,4019全寝可能就迟到了,所以atm希望你帮帮他。
Input
第一行,两个正整数n,k,表示树的点数,询问的是第几小距离;
第二~n行,每行三个正整数x,y,w,表示x和y之间有一条边,x为父亲,边权为w;
Output
n行, 每行一个数,第i行输出从i开始第k小距离
Sample Input
5 2
1 5 2
1 2 4
2 3 6
2 4 5
1 5 2
1 2 4
2 3 6
2 4 5
Sample Output
4
5
10
9
6
5
10
9
6
HINT
100% n<=15000, 边权在1~10之间,为了方便,保证1为根;
动态树分治套Treap。。。
#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } const int maxn=15010; struct Node { Node* ch[2]; int r,s,v; void maintain() {s=ch[0]->s+ch[1]->s+1;} }nodes[maxn*20],*null=&nodes[0]; int ToT;queue<Node*> Q; Node* newnode(int v) { Node* o; if(Q.empty()) o=&nodes[++ToT]; else o=Q.front(),Q.pop(); o->v=v;o->s=1;o->ch[0]=o->ch[1]=null;o->r=rand(); return o; } void del(Node* &o) {Q.push(o);o=null;} void rotate(Node* &o,int d) { Node* k=o->ch[d^1];o->ch[d^1]=k->ch[d];k->ch[d]=o; o->maintain();k->maintain();o=k; } void insert(Node* &o,int v) { if(o==null) o=newnode(v); else { int d=v>o->v;insert(o->ch[d],v); if(o->ch[d]->r>o->r) rotate(o,d^1); else o->maintain(); } } int query(Node* &o,int v) { if(o==null) return 0; if(v>o->v) return query(o->ch[1],v)+o->ch[0]->s+1; return query(o->ch[0],v); } int n,m,first[maxn],next[maxn<<1],to[maxn<<1],dis[maxn<<1],e; void AddEdge(int w,int v,int u) { dis[++e]=w;to[e]=v;next[e]=first[u];first[u]=e; dis[++e]=w;to[e]=u;next[e]=first[v];first[v]=e; } int dep[maxn],mn[maxn<<1][20],Log[maxn<<1],cnt,pos[maxn]; void dfs(int x,int fa) { mn[++cnt][0]=dep[x];pos[x]=cnt; ren if(to[i]!=fa) { dep[to[i]]=dep[x]+dis[i]; dfs(to[i],x); mn[++cnt][0]=dep[x]; } } void pre() { Log[0]=-1; rep(i,1,cnt) Log[i]=Log[i>>1]+1; for(int j=1;(1<<j)<=cnt;j++) for(int i=1;i+(1<<j)-1<=cnt;i++) mn[i][j]=min(mn[i][j-1],mn[i+(1<<j-1)][j-1]); } int dist(int x,int y) { int ans=dep[x]+dep[y]; x=pos[x];y=pos[y];if(x>y) swap(x,y); int k=Log[y-x+1]; return ans-2*min(mn[x][k],mn[y-(1<<k)+1][k]); } int f[maxn],s[maxn],vis[maxn],size,rt; void getroot(int x,int fa) { s[x]=1;int maxs=0; ren if(to[i]!=fa&&!vis[to[i]]) { getroot(to[i],x); s[x]+=s[to[i]]; maxs=max(maxs,s[to[i]]); } f[x]=max(size-s[x],maxs); if(f[x]<f[rt]) rt=x; } int fa[maxn]; void solve(int x,int F) { vis[x]=1;fa[x]=F; ren if(!vis[to[i]]) { f[0]=size=s[to[i]];getroot(to[i],rt=0); solve(rt,x); } } Node *root[maxn],*root2[maxn]; void turn_on(int x) { insert(root[x],0); for(int i=x;fa[i];i=fa[i]) { int D=dist(x,fa[i]); insert(root[fa[i]],D); insert(root2[i],D); } } int query(int x,int v) { int ans=query(root[x],++v); for(int i=x;fa[i];i=fa[i]) { int D=dist(x,fa[i]); ans+=query(root[fa[i]],v-D)-query(root2[i],v-D); } return ans; } int mark[maxn]; int main() { n=read();int k=read(); rep(i,1,n) root[i]=root2[i]=null; rep(i,2,n) AddEdge(read(),read(),read()); dfs(1,0);pre(); f[0]=size=n;getroot(1,rt=0); solve(rt,0); rep(i,1,n) turn_on(i); rep(i,1,n) { int l=0,r=1<<30,mid; while(l<r) if(query(i,mid=l+r>>1)>k) r=mid; else l=mid+1; printf("%d\n",l); } return 0; }