松鼠的新家(JLOI2014)
题目链接:https://www.luogu.org/problemnew/show/P3258
题解:
直接树剖,然后维护差分序列。直接线段树维护序列的话复杂度是2个log,用差分的话就是1个log。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define LL long long #define RI register int using namespace std; const int INF = 0x7ffffff ; const int N = 300000 + 10 ; inline int read() { int k = 0 , f = 1 ; char c = getchar() ; for( ; !isdigit(c) ; c = getchar()) if(c == '-') f = -1 ; for( ; isdigit(c) ; c = getchar()) k = k*10 + c-'0' ; return k*f ; } struct Edge { int to, next ; }e[N<<1] ; int head[N] ; inline void add_edge(int x,int y) { static int cnt = 0 ; e[++cnt].to = y, e[cnt].next = head[x], head[x] = cnt ; } int n ; int hh[N] ; int fa[N], dep[N], son[N], siz[N], top[N], wt[N], id[N] ; inline void add_wt(int x) { static int cnt = 0 ; wt[++cnt] = 0, id[x] = cnt ; } void dfs1(int x,int f) { fa[x] = f, dep[x] = dep[f] + 1, siz[x] = 1 ; int y, maxx = 0 ; for(int i=head[x];i;i=e[i].next) { y = e[i].to ; if(y == f) continue ; dfs1(y,x) ; if(siz[y] > maxx) { maxx = siz[y], son[x] = y ; } siz[x] += siz[y] ; } } void dfs2(int x,int topf) { add_wt(x) ; top[x] = topf ; if(!son[x]) return ; dfs2(son[x],topf) ; int y ; for(int i=head[x];i;i=e[i].next) { y = e[i].to ; if(y == fa[x] || y == son[x]) continue ; dfs2(y,y) ; } } inline void change(int x,int y) { while(top[x] != top[y]) { if(dep[top[x]] < dep[top[y]]) swap(x,y) ; wt[id[top[x]]]++, wt[id[x]+1]-- ; x = fa[top[x]] ; } if(id[x] > id[y]) swap(x,y) ; wt[id[x]]++, wt[id[y]+1]-- ; } int main() { n = read() ; for(int i=1;i<=n;i++) hh[i] = read() ; int x, y, ans = 0 ; for(int i=1;i<n;i++) { x = read(), y = read() ; add_edge(x,y), add_edge(y,x) ; } dfs1(1,0) ; dfs2(1,1) ; for(int i=1;i<n;i++) { change(hh[i],hh[i+1]) ; wt[id[hh[i+1]]]--, wt[id[hh[i+1]]+1]++ ; } x = 0 ; for(int i=1;i<=n;i++) wt[i] += wt[i-1] ; for(int i=1;i<=n;i++) printf("%d\n",wt[id[i]]) ; return 0 ; }