【BZOJ 3631】 [JLOI2014]松鼠的新家

3631: [JLOI2014]松鼠的新家

Time Limit: 10 Sec Memory Limit: 128 MB Submit: 681 Solved: 329 [Submit][Status][Discuss] Description

松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在“树”上。松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,……,最后到an,去参观新家。 可是这样会导致维尼重复走很多房间,懒惰的维尼不听地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。维尼是个馋家伙,立马就答应了。 现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。 Input

第一行一个整数n,表示房间个数 第二行n个整数,依次描述a1-an 接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。 Output

一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让维尼有糖果吃。 Sample Input

5

1 4 5 3 2

1 2

2 4

2 3

4 5

Sample Output

1

2

1

2

1

HINT

2<= n <=300000

树链剖分。

这道题本来是裸的树链剖分,但是我不想写这个,就用了一种奇怪的办法,写完之后发现比链剖还长。。

首先求出这棵树的欧拉序,按照欧拉序建出线段树。

每个点都在欧拉序中出现两次,我们认为第一次出现是正的,第二次是负的。

要处理,分两种情况: ①即可。

②我们需要先从,这就是①的情况; 再从即可。

其实和链剖有些像。。

;struct Segtree{int l,r,v;}t[M*4];struct edge{int y,ne;}e[M];int o[M/2][3],tot,now,dep[M],f[M/2][20],h[M],a[M],ans[M],n;void read(int &tmp){tmp=0;char ch=getchar();for (;ch<‘0’||ch>’9′;ch=getchar());for (;ch>=’0’&&ch<=’9’;ch=getchar())tmp=tmp*10+ch-‘0’;}void Addedge(int x,int y){e[++tot].y=y;e[tot].ne=h[x];h[x]=tot;}//eulervoid dfs(int x,int fa,int d){f[x][0]=fa;dep[x]=d;o[x][1]=++now;for (int i=h[x];i;i=e[i].ne){int y=e[i].y;if (y==fa) continue;dfs(y,x,d+1);}o[x][2]=++now;}//lcavoid ST(){for (int j=1;j<=19;j++)for (int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];}void Move(int &x,int d){for (int j=19;j>=0;j–)if (dep[f[x][j]]>=d)x=f[x][j];}int Getlca(int x,int y){if (dep[x]>dep[y]) swap(x,y);if (dep[x]!=dep[y])Move(y,dep[x]);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];}//segtreevoid Build(int x,int l,int r){t[x].l=l,t[x].r=r,t[x].v=0;if (l==r) return;int m=(l+r)>>1;Build(x<<1,l,m);Build((x<<1)+1,m+1,r);}void Push_down(int x){t[x<<1].v+=t[x].v,t[(x<<1)+1].v+=t[x].v;t[x].v=0;}void Add(int x,int l,int r){if (l>r) return;if (t[x].l>=l&&t[x].r<=r){t[x].v++;return;}if (t[x].v) Push_down(x);int m=(t[x].l+t[x].r)>>1;if (l<=m) Add(x<<1,l,r);if (r>m) Add((x<<1)+1,l,r);}void Down(int x){if (t[x].l==t[x].r){ans[t[x].l]+=t[x].v;return;}if (t[x].v) Push_down(x);Down(x<<1),Down((x<<1)+1);}int main(){scanf(“%d”,&n);for (int i=1;i<=n;i++)read(a[i]);for (int i=1;i<n;i++){int x,y;read(x),read(y);Addedge(x,y),Addedge(y,x);}now=0;dfs(1,0,1);ST();Build(1,1,2*n);for (int i=2;i<=n;i++){int x=Getlca(a[i-1],a[i]);int a1=a[i-1],a2=a[i];if (o[a1][1]>o[a2][1]) swap(a1,a2);if (a1==x){Add(1,o[a1][1],o[a2][1]);continue;}Add(1,o[x][1],o[a1][1]);for (int j=19;j>=0;j–)if (dep[f[a1][j]]>=dep[x]+1)a1=f[a1][j];Add(1,o[a1][2]+1,o[a2][1]);}Down(1);for (int i=2;i<=n;i++)ans[o[a[i]][2]]++;for (int i=1;i<=n;i++){int k=ans[o[i][1]]-ans[o[i][2]];printf(“%d\n”,k);}return 0;}

人总是珍惜未得到的,而遗忘了所拥有的

【BZOJ 3631】 [JLOI2014]松鼠的新家

相关文章:

你感兴趣的文章:

标签云: