bzoj3631树链剖分
虽然是水题1A的感觉太爽了O(∩_∩)O~
题意相当于n-1次树上路径上每个点权值+1,最后问每个点的权值
本来想写线段树,写好了change打算框架打完了再来补,结果打完发现只是区间加和单点查
前缀和不要怂!!!
结果,,,change的长度让人怀疑写change的必要,,,mdzz懒得改了
1 inline void change(int x,int y){a[x]++;a[y+1]--;}
这道题注意要点:
每次都按照顺序加权值的话会导致多算端点的权值,解决方法很简单:算完以后把除出发点以外的所有点权值-1(因为题目保证了遍历每个点,所以除出发点以外每个点肯定被多算一次)
树链剖分好久没写了,主要部分没问题,就是关于高度的东西写成鬼畜了,没记住高度小的排在前面,导致调了几分钟样例
1 #include <cstdio> 2 int n,m=0,N=0,p,q; 3 int to[600001],nex[600001],son[300001],bro[300001]; 4 int fir[300001],size[300001],pos[300001],top[300001],h[300001],fa[300001]; 5 int l[300001],a[300001],ans[300001],b[300001]; 6 inline void add(int x,int y){to[++m]=y;nex[m]=fir[x];fir[x]=m;} 7 inline void change(int x,int y){a[x]++;a[y+1]--;} 8 inline void swap(int &x,int &y){int t=x;x=y;y=t;} 9 int build(int now,int fat) 10 { 11 size[now]=1;h[now]=h[fat]+1;fa[now]=fat; 12 for(int i=fir[now];i;i=nex[i]) 13 if(to[i]!=fat) 14 bro[to[i]]=son[now],son[now]=to[i],size[now]+=build(to[i],now); 15 return size[now]; 16 } 17 void pou(int now,int to) 18 { 19 l[++N]=now;pos[now]=N;top[now]=to; 20 int max=son[now]; 21 if(!max) return; 22 for(int i=bro[max];i;i=bro[i]) 23 if(size[i]>size[max]) max=i; 24 pou(max,to); 25 for(int i=son[now];i;i=bro[i]) 26 if(i!=max) pou(i,i); 27 } 28 void work(int x,int y) 29 { 30 while(top[x]!=top[y]) 31 { 32 if(h[top[x]]<h[top[y]]) swap(x,y); 33 change(pos[top[x]],pos[x]); 34 x=fa[top[x]]; 35 } 36 if(h[x]>h[y]) swap(x,y); 37 change(pos[x],pos[y]); 38 } 39 int main() 40 { 41 scanf("%d",&n); 42 for(int i=1;i<=n;i++) 43 scanf("%d",&b[i]); 44 for(int i=1;i<n;i++) 45 scanf("%d%d",&p,&q),add(p,q),add(q,p); 46 build(1,0); 47 pou(1,1); 48 for(int i=1;i<n;i++) 49 work(b[i],b[i+1]); 50 for(int i=1;i<=n;i++) 51 ans[l[i]]=ans[l[i-1]]+a[i]; 52 for(int i=1;i<=n;i++) 53 printf("%d\n",ans[i]-1+(i==b[1])); 54 }