首页 > 技术文章 > bzoj3631树链剖分

wanglichao 2016-08-19 16:59 原文

虽然是水题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 } 

 

推荐阅读