洛谷3258
题目描述
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。
松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家。可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。
维尼是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。
因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。
输入输出格式
输入格式:第一行一个整数n,表示房间个数第二行n个整数,依次描述a1-an接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。
输出格式:一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让维尼有糖果吃。
输入输出样例
说明
2<= n <=300000
分析:首先很容易看出是树链剖分。
本题先告诉你是一棵树,然后要这只小熊在树上走,每经过一个点都要放一颗糖果,问每个点放了几个糖果。这显然是对树上的链进行操作,这就想到了树链剖分。
其实就是一个模板。
但本题要注意的是每次到达一个点,要放一次糖果,但你从这个点走向下一个点的时候就不要放糖果了,所以每次再在这个点上进行减一就行了。
传送门:洛谷3258
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define ll(x) (x*2) #define rr(x) (x*2+1) typedef long long ll; int lazy[600100],last[600100],w[600100],dep[600010],fa[600010],n,len=0; int siz[600010],son[600100],cnt=0,id[600100],wt[600100],sum[2000100]; int top[600100],kkk[600100],yuan[600010],ansk[600010]; struct node { int to,next; }a[600100]; void add(int a1,int a2) { len++; a[len].to=a2; a[len].next=last[a1]; last[a1]=len; } void dfs1(int x,int father,int deep) { dep[x]=deep; fa[x]=father; siz[x]=1; int maxson=-1; for(int i=last[x];i;i=a[i].next) { int to=a[i].to; if(to==father) continue; dfs1(to,x,deep+1); siz[x]+=siz[to]; if(siz[to]>maxson) son[x]=to,maxson=siz[to]; } } void dfs2(int x,int topf) { cnt++; id[x]=cnt; yuan[cnt]=x; wt[cnt]=w[x]; top[x]=topf; if(!son[x]) return; dfs2(son[x],topf); for(int i=last[x];i;i=a[i].next) { int to=a[i].to; if(to==fa[x]||to==son[x]) continue; dfs2(to,to); } } void xia(int node,int lsum,int rsum) { if(lazy[node]) { lazy[ll(node)]+=lazy[node]; lazy[rr(node)]+=lazy[node]; sum[ll(node)]+=lsum*lazy[node]; sum[rr(node)]+=rsum*lazy[node]; lazy[node]=0; return; } } void gai(int node,int left,int right,int l,int r,int k) { if(l<=left&&right<=r) { sum[node]+=(k*(right-left+1)); lazy[node]+=k; return; } if(left>r||right<l) return; int mid=(left+right)/2; xia(node,mid-left+1,right-mid); if(left<=mid) gai(ll(node),left,mid,l,r,k); if(right>mid) gai(rr(node),mid+1,right,l,r,k); sum[node]=(sum[ll(node)]+sum[rr(node)]); } void gai1(int x,int y,int k) { int yy=y; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); gai(1,1,n,id[top[x]],id[x],k); x=fa[top[x]]; // cout<<4554545; } if(dep[x]>dep[y]) swap(x,y); gai(1,1,n,id[x],id[y],k); gai(1,1,n,id[yy],id[yy],-k); } void de(int node,int left,int right) { if(left==right) { ansk[yuan[left]]=sum[node]; //cout<<node<<endl; return; } int mid=(left+right)/2; xia(node,mid-left+1,right-mid); de(ll(node),left,mid); de(rr(node),mid+1,right); } int main() { int m,r,x,y; cin>>n; for(int i=1;i<=n;i++) w[i]=0; for(int i=1;i<=n;i++) scanf("%d",&kkk[i]); for(int i=1;i<=n-1;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs1(1,0,1); dfs2(1,1); for(int i=1;i<n;i++) { gai1(kkk[i],kkk[i+1],1); } de(1,1,n); for(int i=1;i<=n;i++) printf("%d ",ansk[i]); }