[BZOJ3631][洛谷P3258][JLOI2014]松鼠的新家
2016-11-11 21:38
302 查看
题目描述
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,……,最后到an,去参观新家。可是这样会导致维尼重复走很多房间,懒惰的维尼不听地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。
维尼是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。
因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。
输入输出格式
输入格式:
第一行一个整数n,表示房间个数第二行n个整数,依次描述a1-an接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。输出格式:
一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让维尼有糖果吃。输入输出样例
输入样例#1:
51 4 5 3 2
1 2
2 4
2 3
4 5
输出样例#1:
12
1
2
1
说明
2<= n <=300000题解
一道标准的裸题。听说有神犇用树链剖分A掉了这道水题,然而我不会树剖233
我的思路是树上倍增+树上差分
因为访问是从一点出发,增加路上经过的点和终点的值,所以我们要分情况讨论。
我们用sum[i]表示i点和他的祖先要增加的数值,lc表示起点和终点 的LCA,st为起点,ed为终点。
如果LCA为起点,说明是走到了起点的儿子,
所以sum[ed]++;sum[st]–;
如果LCA为终点,说明是走到了起点的父亲,
所以sum[father[ed]]–;sum[father[st]]++;
如果LCA不是起点也不是终点,怎么办?
我们可以发现这次移动等价于先从起点走到了LCA:
sum[father[LCA]]]–;sum[father[st]]++;
然后从LCA走到了终点:
sum[ed]++;sum[LCA]–;
所以就是
sum[father[st]]++;sum[ed]++;sum[LCA]–;sum[father[LCA]]]–;
之后再一遍dfs就可以算出每一个点的值辣!
At Last ,最后一个到达的点要 -1;
My Code
/************************************************************** Problem: 3631 User: infinityedge Language: C++ Result: Accepted Time:2492 ms Memory:42724 kb ****************************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<map> using namespace std; struct wn{ int to,nxt; }w[600000]; int h[300001],sum[300001],cnt=0; int f[300001][21],dep[300001]; int n; int sx[300001]; inline int re(){ int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar(); } while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();} return x*f ; } inline void addedge(int x,int y){ cnt++; w[cnt].to=y; w[cnt].nxt=h[x]; h[x]=cnt; cnt++; w[cnt].to=x; w[cnt].nxt=h[y]; h[y]=cnt; } void dfs(int x,int fa){ dep[x]=dep[fa]+1; f[x][0]=fa; for(int i=h[x];i;i=w[i].nxt){ if(w[i].to!=fa){ dfs(w[i].to,x); } } return; } void csh(){ for(int i=1;i<=20;i++){ for(int j=1;j<=n;j++){ f[j][i]=f[f[j][i-1]][i-1]; } } } inline int lca(int x,int y){ if(dep[x]<dep[y])swap(x,y); for(int i=19;i>=0;i--){ if(dep[f[x][i]]>=dep[y])x=f[x][i]; } if(x==y)return x; for(int i=19;i>=0;i--){ if(f[x][i]!=f[y][i]){ x=f[x][i],y=f[y][i]; } } return f[x][0]; } void dfs2(int x,int fa){ for(int i=h[x];i;i=w[i].nxt){ if(w[i].to!=fa){ dfs2(w[i].to,x); sum[x]+=sum[w[i].to]; } } return; } int main(){ n=re(); for(int i=1;i<=n;i++){ sx[i]=re(); } int xx,yy; for(int i=1;i<n;i++){ xx=re(); yy=re(); addedge(xx,yy); } dfs(1,0); csh(); sum[sx[1]]=1; sum[f[sx[1]][0]]=-1; int lc; for(int i=2;i<=n;i++){ xx=sx[i-1]; yy=sx[i]; lc=lca(xx,yy); if(lc==xx){ sum[yy]++; sum[xx]--; }else if(lc==yy){ sum[f[xx][0]]++; sum[f[yy][0]]--; }else{ sum[f[xx][0]]++; sum[yy]++; sum[lc]--; sum[f[lc][0]]--; } } dfs2(1,0); sum[sx ]--; for(int i=1;i<=n;i++){ printf("%d\n",sum[i]); } return 0; }
相关文章推荐
- 洛谷 P3258 BZOJ 3631 [JLOI2014]松鼠的新家
- BZOJ3631 [JLOI2014]松鼠的新家 【树上差分】
- [bzoj 3631--JLOI2014]松鼠的新家
- 洛谷——P3258 [JLOI2014]松鼠的新家
- [Bzoj3631][JLOI2014]松鼠的新家 (树上前缀和)
- 【bzoj3631】[JLOI2014]松鼠的新家
- 洛谷P3258 [JLOI2014]松鼠的新家
- BZOJ3631: [JLOI2014]松鼠的新家
- bzoj3631[JLOI2014 松鼠的新家 倍增lca+差分
- 【bzoj 3631】[JLOI2014]松鼠的新家(树链剖分)
- BZOJ 3631 [JLOI2014]松鼠的新家==树剖
- BZOJ 3631 [JLOI2014]松鼠的新家
- 洛谷P3258 [JLOI2014]松鼠的新家
- BZOJ3631[JLOI2014]松鼠的新家 题解
- bzoj3631[JLOI2014 松鼠的新家 倍增lca+差分
- 【BZOJ3631】[JLOI2014]松鼠的新家 树链剖分
- bzoj 3631: [JLOI2014]松鼠的新家
- BZOJ 3631 [JLOI2014]松鼠的新家 | 树上差分
- 【树链剖分】【树状数组】【最近公共祖先】【块状树】bzoj3631 [JLOI2014]松鼠的新家
- bzoj3631: [JLOI2014]松鼠的新家 (树上差分)