zoukankan      html  css  js  c++  java
  • 【LNOI2014】【BZOJ3626】NOIp2018模拟(三) LCA

    Description

    给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
    设$dep[i]$表示点i的深度,$lca(i,j)$表示i与j的最近公共祖先。
    有q次询问,每次询问给出l,r,z,求$sumlimits_{i=l}^{r}dep[lca(i,z)]$。
    (即求在$[l,r]$区间内的每个节点i与z的最近公共祖先的深度之和)

    $n,q<=50000$

    Input

    第一行2个整数n,q。
    接下来n-1行,分别表示点1到点n-1的父节点编号。
    接下来q行,每行3个整数l,r,z。

    Output

    输出q行,每行表示一个询问的答案。每个答案对201314取模输出

    Sample Input

    5 2
    0
    0
    1
    1
    1 4 3
    1 4 2

    Sample Output

    8
    5

     

    这题不算很难,但是看到正解的方法很有趣,就记录一下~

    考虑暴力,每次询问把z到根的所有节点打上标记,枚举i的时候直接往根找第一个有标记的点,然后统计深度即可。

    然而复杂度明显是大于$O(n^2q)$的,显然不能接受,容易发现如果把深度看成点权,那么统计深度就相当于把z到根的每个节点权值都加一,然后枚举时统计根节点到i的权值和。使用树链剖分可以降到$O(nqlog^2n)$,但是还是会超时。

    考虑进一步优化,发现询问可以差分,拆成$[1,l-1]$和$[1,r]$两个询问,进一步可以发现对答案有贡献的点只会在$lca(i,z)$以上,因此把每个i到根路径上的结点权值加一,再统计z到根节点的权值和,得出的答案是相同的。再结合差分,每次直接将$[1,l-1]$或$[1,r]$中所有节点到根节点路径上的点权值加一,然后统计z到根节点的权值和,按照dfs序区间修改+区间查询,用树链剖分加线段树可以做到$O(qlog^2n)$,用LCT可以做到$O(qlogn)$

    注意long long

    代码:

     

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<cmath>
      6 #define mod 201314
      7 using namespace std;
      8 typedef long long ll;
      9 struct edge{
     10     int v,next;
     11 }a[200001];
     12 struct task{
     13     int r,z,id,ok;
     14 }q[200001];
     15 int n,qq,u,v,z,tmp=0,qqq=0,tot=0,tim=0,head[100001],son[100001],siz[100001],fa[100001],dep[100001],dfn[100001],top[100001];
     16 ll t[500001],laz[500001],tv[500001],ans[100001],anss;
     17 bool cmp(task a,task b){
     18     return a.r<b.r;
     19 }
     20 void add(int u,int v){
     21     a[++tot].v=v;
     22     a[tot].next=head[u];
     23     head[u]=tot;
     24 }
     25 void dfs1(int u,int f,int dpt){
     26     dep[u]=dpt;
     27     fa[u]=f;
     28     siz[u]=1;
     29     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
     30         int v=a[tmp].v;
     31         if(!dep[v]){
     32             dfs1(v,u,dpt+1);
     33             siz[u]+=siz[v];
     34             if(siz[v]>siz[son[u]]||son[u]==-1)son[u]=v;
     35         }
     36     }
     37 }
     38 void dfs2(int u,int tp){
     39     dfn[u]=++tim;
     40     top[u]=tp;
     41     if(son[u]!=-1)dfs2(son[u],tp);
     42     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
     43         int v=a[tmp].v;
     44         if(v!=son[u])dfs2(v,v);
     45     }
     46 }
     47 void pushup(int u){
     48     t[u]=t[u*2]+t[u*2+1];
     49 }
     50 void pushdown(int u){
     51     if(laz[u]){
     52         laz[u*2]+=laz[u];
     53         laz[u*2+1]+=laz[u];
     54         t[u*2]+=tv[u*2]*laz[u];
     55         t[u*2+1]+=tv[u*2+1]*laz[u];
     56         laz[u]=0;
     57     }
     58 }
     59 void build(int l,int r,int u){
     60     if(l==r){
     61         tv[u]=1;
     62         return;
     63     }
     64     int mid=(l+r)/2;
     65     build(l,mid,u*2);
     66     build(mid+1,r,u*2+1);
     67     tv[u]=tv[u*2]+tv[u*2+1];
     68 }
     69 void updata(int l,int r,int u,int L,int R,int v){
     70     if(L<=l&&r<=R){
     71         t[u]+=(ll)tv[u]*v;
     72         laz[u]+=v;
     73         return;
     74     }
     75     int mid=(l+r)/2;
     76     pushdown(u);
     77     if(L<=mid)updata(l,mid,u*2,L,R,v);
     78     if(mid<R)updata(mid+1,r,u*2+1,L,R,v);
     79     pushup(u);
     80 }
     81 ll query(int l,int r,int u,int L,int R){
     82     if(L<=l&&r<=R){
     83         return t[u];
     84     }
     85     int mid=(l+r)/2,ans=0;
     86     pushdown(u);
     87     if(L<=mid)ans+=query(l,mid,u*2,L,R);
     88     if(R>mid)ans+=query(mid+1,r,u*2+1,L,R);
     89     return ans;
     90 }
     91 void work(int u){
     92     while(u){
     93         int v=top[u];
     94         updata(1,n,1,dfn[v],dfn[u],1);
     95         u=fa[v];
     96     }
     97 }
     98 ll _work(int u){
     99     ll ans=0;
    100     while(u){
    101         int v=top[u];
    102         ans+=query(1,n,1,dfn[v],dfn[u]);
    103         u=fa[v];
    104     }
    105     return ans;
    106 }
    107 int main(){
    108     memset(son,-1,sizeof(son));
    109     memset(head,-1,sizeof(head));
    110     scanf("%d%d",&n,&qq);
    111     for(int i=1;i<n;i++){
    112         scanf("%d",&u);
    113         add(u+1,i+1);
    114     }
    115     dfs1(1,0,1);
    116     dfs2(1,1);
    117     build(1,n,1);
    118     for(int i=1;i<=qq;i++){
    119         scanf("%d%d%d",&u,&v,&z);
    120         u++,v++,z++;
    121         q[++qqq]=(task){u-1,z,i,-1};
    122         q[++qqq]=(task){v,z,i,1};
    123     }
    124     sort(q+1,q+qqq+1,cmp);
    125     for(int i=1;i<=qqq;i++){
    126         while(tmp<q[i].r){
    127             work(++tmp);
    128         }
    129         ans[q[i].id]+=(ll)q[i].ok*_work(q[i].z);
    130     }
    131     for(int i=1;i<=qq;i++){
    132         printf("%lld
    ",ans[i]%mod);
    133     }
    134     return 0;
    135 }

     

     

  • 相关阅读:
    织梦当前位置去除最后字符
    一霎清明雨,实现考勤管理。
    浅谈:C#中的非泛型集合
    简述结构和类的区别
    项目经理评分系统
    那些年我们一起~做过的魔兽系统
    浅谈:什么是.NET
    MyKTV系统项目的感想
    开发“航班查询及预定”系统
    java面试的一些问题
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/9268231.html
Copyright © 2011-2022 走看看