省选的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); }