BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线

http://www.lydsy.com/JudgeOnline/problem.php?id=3626

LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的。
我如果现场写,很难想出来这种题,是时候复习一波离线算法泡脑子了。(没有暴力分的题,想不出来正解就爆零,太可怕了)
排序后离线操作通过前缀和计算答案,题解是hzwer的博客上复制的

直接引用清华爷gconeice的题解吧

显然,暴力求解的复杂度是无法承受的。

考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案。观察到,深度其实就是上面有几个已标记了的点(包括自身)。所以,我们不妨把 z 到根的路径上的点全部 +1,对于 l 到 r 之间的点询问他们到根路径上的点权和。仔细观察上面的暴力不难发现,实际上这个操作具有叠加性,且可逆。也就是说我们可以对于 l 到 r 之间的点 i,将 i 到根的路径上的点全部 +1, 转而询问 z 到根的路径上的点(包括自身)的权值和就是这个询问的答案。把询问差分下,也就是用 [1, r] ? [1, l ? 1] 来计算答案,那么现在我们就有一个明显的解法。从 0 到 n ? 1 依次插入点 i,即将 i 到根的路径上的点全部+1。离线询问答案即可。我们现在需要一个数据结构来维护路径加和路径求和,显然树链剖分或LCT 均可以完成这个任务。树链剖分的复杂度为 O((n + q)· log n · log n),LCT的复杂度为 O((n + q)· log n),均可以完成任务。至此,题目已经被我们完美解决。

 

  1 #include<iostream>  
  2 #include<cstdio>  
  3 #include<cstring>  
  4 #include<algorithm>  
  5 #include<cmath>  
  6 using namespace std;
  7 const int maxn=50100;
  8 const long long modn=1000000007;
  9 const long long minf=1<<30;
 10 int n,m;
 11 struct nod{
 12     int y,next;
 13 }e[maxn];int head[maxn]={},tot=0;
 14 int fa[maxn]={},top[maxn]={},pos[maxn]={},kid[maxn]={},dep[maxn]={};
 15 void init(int x,int y){
 16     e[++tot].y=y;e[tot].next=head[x];head[x]=tot;
 17 }
 18 int dfs1(int x){
 19     int y,hug=0,siz,tsn=1;dep[x]=dep[fa[x]]+1;
 20     for(int i=head[x];i;i=e[i].next){
 21         y=e[i].y;
 22         if(y==fa[x])continue;
 23         siz=dfs1(y);
 24         if(siz>hug)hug=siz,kid[x]=y;
 25         tsn+=siz;
 26     }return tsn;
 27 }
 28 void dfs2(int x,int pa){
 29     int y;top[x]=pa;pos[x]=++tot;
 30     if(kid[x])dfs2(kid[x],pa);
 31     for(int i=head[x];i;i=e[i].next){
 32         y=e[i].y;
 33         if(y==kid[x]||y==fa[x])continue;
 34         dfs2(y,y);
 35     }
 36 }
 37 struct seg{
 38     long long sum,w,l,r;
 39     seg(){sum=l=r=0;}
 40 }t[maxn*4];
 41 void build(int x,int l,int r){
 42     t[x].l=l;t[x].r=r;
 43     if(l==r)return;
 44     int mid=(l+r)/2;
 45     build(x*2,l,mid);
 46     build(x*2+1,mid+1,r);
 47 }
 48 void pushup(int x){
 49     if(t[x].r>t[x].l)t[x].sum=t[x*2].sum+t[x*2+1].sum;
 50     t[x].sum+=(t[x].r-t[x].l+1)*t[x].w;
 51 }
 52 void add(int x,int l,int r){
 53     if(l<=t[x].l&&t[x].r<=r){
 54         if(t[x].l==t[x].r)t[x].sum+=1;
 55         else {t[x].w+=1;pushup(x);}
 56         return;
 57     }
 58     int mid=(t[x].l+t[x].r)/2,ls=x*2,rs=x*2+1;
 59     if(r>mid) add(rs,l,r);
 60     if(l<=mid) add(ls,l,r);
 61     pushup(x);
 62 }
 63 long long sum(int x,int l,int r,int w){
 64     if(l<=t[x].l&&t[x].r<=r)return t[x].sum+w*(t[x].r-t[x].l+1);
 65     int mid=(t[x].l+t[x].r)/2,ls=x*2,rs=x*2+1;long long tsn=0;
 66     if(l<=mid) tsn+=sum(ls,l,r,w+t[x].w);
 67     if(r>mid) tsn+=sum(rs,l,r,w+t[x].w);
 68     return tsn;
 69 }
 70 long long doit(int x){
 71     int a=top[x];long long tsn=0;
 72     for(;a!=1;){
 73         tsn+=sum(1,pos[a],pos[x],0);
 74         x=fa[a];a=top[x];
 75     }
 76     tsn+=sum(1,pos[a],pos[x],0);
 77     return tsn;
 78 }
 79 void datup(int x){
 80     int a=top[x];
 81     for(;a!=1;){
 82         add(1,pos[a],pos[x]);
 83         x=fa[a];a=top[x];
 84     }
 85     add(1,pos[a],pos[x]);
 86 }
 87 struct lcc{
 88     int num;
 89     int z;int id;
 90     long long ans;
 91 }q[maxn*2];
 92 bool cmp1(lcc aa,lcc bb){return aa.num<bb.num;}
 93 bool cmp2(lcc aa,lcc bb){return aa.id<bb.id;}
 94 int main(){
 95     scanf("%d%d",&n,&m);
 96     int x,y,z;
 97     for(int i=1;i<n;i++){
 98         scanf("%d",&y);
 99         init(y+1,i+1);
100         fa[i+1]=y+1;
101     }tot=0;dfs1(1);dfs2(1,1);build(1,1,n);tot=0;
102     for(int j=1;j<=m;j++){
103         scanf("%d%d%d",&x,&y,&z);
104         x++;y++;z++;
105         if(y<x)swap(x,y);
106         q[++tot].num=x-1;q[tot].z=z;q[tot].id=tot;
107         q[++tot].num=y;q[tot].z=z;q[tot].id=tot;
108     }sort(q+1,q+1+tot,cmp1);
109     int now=0;
110     for(int i=1;i<=tot;i++){
111         while(now<q[i].num){
112             now++;datup(now);
113         }
114         q[i].ans=doit(q[i].z);
115     }
116     sort(q+1,q+1+tot,cmp2);
117     for(int i=1;i<=m;i++){
118         long long z=(q[i*2].ans-q[i*2-1].ans)%201314;
119         printf("%lld\n",z);
120     }
121     return 0;
122 }
View Code

 

 

 

posted @ 2017-11-05 11:48  鲸头鹳  阅读(143)  评论(0编辑  收藏  举报