省选的day1第一题,当时不会树链剖分,手动模拟得了50分。。残念
时隔多年才会了树链剖分,重新来A这个题,感觉还是挺容易的
刚开始写树链剖分的时候注意一下从一个链跳到另一个链的时候,还有线段树的区间是否包含,刚开始学的时候总是弄不明白,画张图简单模拟一下就好了
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 300010
#define LEFT (pos << 1)
#define RIGHT (pos << 1|1)
using namespace std;
int points;
int route[MAX];
int head[MAX],total;
int next[MAX << 1],aim[MAX << 1];
int father[MAX],size[MAX],son[MAX],deep[MAX];
int top[MAX],pos[MAX],cnt;
int tree[MAX << 2];
inline void Add(int x,int y);
inline int PreDFS(int x,int last);
inline void DFS(int x,int last,int root);
inline void PushDown(int pos);
inline void Increase(int x,int y);
inline void Modify(int l,int r,int x,int y,int pos,int num);
inline int Ask(int l,int r,int aim,int pos);
int main()
{
cin >> points;
for(int i = 1;i <= points; ++i)
scanf("%d",&route[i]);
for(int x,y,i = 1;i < points; ++i) {
scanf("%d%d",&x,&y);
Add(x,y),Add(y,x);
}
PreDFS(1,-1);
DFS(1,-1,1);
for(int i = 2;i <= points; ++i)
Increase(route[i - 1],route[i]);
for(int i = 1;i <= points; ++i)
printf("%d\n",Ask(1,points,pos[i],1));
return 0;
}
inline void Add(int x,int y)
{
next[++total] = head[x];
aim[total] = y;
head[x] = total;
}
inline int PreDFS(int x,int last)
{
deep[x] = deep[last] + 1;
father[x] = last;
int temp,max_size = 0;
size[x] = 1;
for(int i = head[x];i;i = next[i]) {
if(aim[i] == last) continue;
temp = PreDFS(aim[i],x);
size[x] += temp;
if(temp > max_size)
max_size = temp,son[x] = aim[i];
}
return size[x];
}
inline void DFS(int x,int last,int root)
{
pos[x] = ++cnt;
top[x] = root;
if(son[x]) DFS(son[x],x,root);
for(int i = head[x];i;i = next[i]) {
if(aim[i] == son[x] || aim[i] == last) continue;
DFS(aim[i],x,aim[i]);
}
}
inline void Increase(int x,int y)
{
Modify(1,points,pos[y],pos[y],1,-1);
int fx = top[x],fy = top[y];
while(fx != fy) {
if(deep[fx] < deep[fy])
swap(fx,fy),swap(x,y);
Modify(1,points,pos[fx],pos[x],1,1);
x = father[fx];
fx = top[x];
}
if(deep[x] < deep[y]) swap(x,y);
Modify(1,points,pos[y],pos[x],1,1);
}
inline void Modify(int l,int r,int x,int y,int pos,int num)
{
if(l == x && r == y) {
tree[pos] += num;
return ;
}
PushDown(pos);
int mid = (l + r) >> 1;
if(y <= mid) Modify(l,mid,x,y,LEFT,num);
else if(x > mid) Modify(mid + 1,r,x,y,RIGHT,num);
else {
Modify(l,mid,x,mid,LEFT,num);
Modify(mid + 1,r,mid + 1,y,RIGHT,num);
}
}
inline void PushDown(int pos)
{
if(tree[pos]) {
tree[LEFT] += tree[pos];
tree[RIGHT] += tree[pos];
tree[pos] = 0;
}
}
inline int Ask(int l,int r,int aim,int pos)
{
if(l == r) return tree[pos];
PushDown(pos);
int mid = (l + r) >> 1;
if(aim <= mid) return Ask(l,mid,aim,LEFT);
return Ask(mid + 1,r,aim,RIGHT);
}
刚开始写博客啊,有博客写的不好的地方或者代码写的不好的地方欢迎指出来-_-#