zoukankan      html  css  js  c++  java
  • 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
    ",z);
    120     }
    121     return 0;
    122 }
    View Code
  • 相关阅读:
    【JavaScript知识点一】JavaScript 数据类型
    grunt操作之Gruntfile.js
    js重定向后跳转到当前页面锚点
    Java-变量和方法
    Java-运算符
    Java-类型转化
    Java-数组
    Java-循环结构(for,while)
    Java-选择结构(if-else)
    Java-数据类型(引用类型)
  • 原文地址:https://www.cnblogs.com/137shoebills/p/7787000.html
Copyright © 2011-2022 走看看