http://www.lydsy.com/JudgeOnline/problem.php?id=3631
樹鏈剖分其實也可以不老用線段樹維護,比如這道題可以差分,因為是區間修改+一次性單點查詢,所以可以先樹鏈剖分,然后再把權值差分,每次直接在d[a]++,d[b+1]--,就完成了區間修改。
其實也可以樹上前綴和,也是差分,先倍增求出LCA,然后在lca處++,在兩個點的所有兒子處--。懶得寫了。。。
//樹鏈剖分+差分 #include <cstdio> #include <algorithm> #define lowbit(x) (x&-x) #define maxn 600010 using namespace std; int N, d[maxn], head[maxn], next[maxn], to[maxn], tot, fa[maxn], son[maxn], size[maxn], tid[maxn], tim, top[maxn], deep[maxn], a[maxn]; void adde(int a, int b){to[++tot]=b;next[tot]=head[a];head[a]=tot;} void dfs1(int pos) { int p, v; size[pos]=1; son[pos]=-1; for(p=head[pos];p;p=next[p]) { if((v=to[p])==fa[pos])continue; fa[v]=pos; deep[v]=deep[pos]+1; dfs1(v); if(son[pos]==-1 or size[son[pos]]<size[v])son[pos]=v; size[pos]+=size[v]; } } void dfs2(int pos, int tp) { int p, v; top[pos]=tp; tid[pos]=++tim; if(son[pos]!=-1)dfs2(son[pos],tp); for(p=head[pos];p;p=next[p]) { if((v=to[p])==fa[pos] or v==son[pos])continue; dfs2(v,v); } } void work(int a, int b) { int ta=top[a], tb=top[b]; while(ta!=tb) { if(deep[ta]<deep[tb])swap(a,b),swap(ta,tb); d[tid[ta]]++,d[tid[a]+1]--; a=fa[ta];ta=top[a]; } if(deep[a]>deep[b])swap(a,b); d[tid[a]]++,d[tid[b]+1]--; } void print() { int i; for(i=1;i<=tim;i++)d[i]+=d[i-1]; for(i=1;i<=N;i++)printf("%d\n",d[tid[i]]); } int main() { int i, x, y; scanf("%d",&N); for(i=1;i<=N;i++)scanf("%d",a+i); for(i=1;i<N;i++)scanf("%d%d",&x,&y),adde(x,y),adde(y,x); dfs1(1); dfs2(1,1); for(i=1;i<N;i++) { work(a[i],a[i+1]); if(i!=1)d[tid[a[i]]]--,d[tid[a[i]]+1]++; if(i==N-1)d[tid[a[N]]]--,d[tid[a[N]]+1]++; } print(); return 0; }
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。