[JLOI2014]松鼠的新家
题目描述
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。
松鼠想邀请****前来参观,并且还指定一份参观指南,他希望**能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家。可是这样会导致**重复走很多房间,懒惰的**不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。
**是个馋家伙,立马就答应了。现在松鼠希望知道为了保证**有糖果吃,他需要在每一个房间各放至少多少个糖果。
因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当**在参观的最后到达餐厅时就不需要再拿糖果吃了。
输入输出格式
输入格式:
第一行一个整数n,表示房间个数第二行n个整数,依次描述a1-an接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。
输出格式:
一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让**有糖果吃。
输入输出样例
说明
2<= n <=300000
题解
可以说是一道树链剖分的模板题吧
但是注意一下有坑
参观的n 个房间并不一定包括了所有的房间!
e.g. 参观1->2->1->3->1
以及最坏情况需要开long long
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define ll long long using namespace std; const int N=300010; struct node{ int to,next; }e[N<<1]; int dep[N],fa[N],sum[4*N],lazy[4*N],num,head[N],dic[N]; int size[N],son[N],ch[N],now,n,l[N],top[N],tot; void add(int from,int to) { num++; e[num].to=to; e[num].next=head[from]; head[from]=num; } void push(int root,int l,int r) { int mid=(l+r)>>1; lazy[root<<1]+=lazy[root]; lazy[root<<1|1]+=lazy[root]; sum[root<<1]+=lazy[root]*(mid-l+1); sum[root<<1|1]+=lazy[root]*(r-mid); lazy[root]=0; return ; } void update(int root,int left,int right,int l,int r,int k) { if(l>right||r<left)return ; if(l<=left&&right<=r) { sum[root]+=k*(right-left+1); lazy[root]+=k; return ; } int mid=(left+right)>>1; if(lazy[root])push(root,left,right); if(mid>=l)update(root<<1,left,mid,l,r,k); if(r>mid) update(root<<1|1,mid+1,right,l,r,k); sum[root]=sum[root<<1]+sum[root<<1|1]; return ; } ll query(int root,int left,int right,int l,int r) { if(l>right||r<left)return 0; if(l<=left&&right<=r)return sum[root]; int mid=(left+right)>>1; if(lazy[root])push(root,left,right); ll a=0,b=0; if(mid>=l)a=query(root<<1,left,mid,l,r); if(mid<r) b=query(root<<1|1,mid+1,right,l,r); return a+b; } void dfs1(int x) { size[x]=1; for(int i=head[x];i;i=e[i].next) { int v=e[i].to; if(!dep[v]) { dep[v]=dep[x]+1; fa[v]=x; dfs1(v); size[x]+=size[v]; if(size[v]>size[son[x]])son[x]=v; } } return ; } void dfs2(int x,int t) { l[x]=++tot;top[x]=t; if(son[x])dfs2(son[x],t); for(int i=head[x];i;i=e[i].next) { int v=e[i].to; if(v!=fa[x]&&v!=son[x]) { dfs2(v,v); } } return ; } void cap(int x,int y) { int fx=top[x],fy=top[y]; while(fx!=fy) { if(dep[fx]<dep[fy]) { swap(fx,fy);swap(x,y); } update(1,1,n,l[fx],l[x],1); x=fa[fx]; fx=top[x]; } if(l[x]>l[y]) swap(x,y); update(1,1,n,l[x],l[y],1); return ; } ll read() { ll x=0,w=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*w; } int main() { n=read(); for(int i=1;i<=n;i++) { ch[i]=read(); if(i!=1)dic[ch[i]]++; } for(int i=1;i<n;i++) { int x,y; x=read();y=read(); add(x,y);add(y,x); } dep[1]=1; fa[1]=0; dfs1(1); dfs2(1,1); for(int i=2;i<=n;i++) { cap(ch[i-1],ch[i]); } for(int i=1;i<=n;i++) { cout<<query(1,1,n,l[i],l[i])-dic[i]<<endl; } return 0; }