zoukankan      html  css  js  c++  java
  • [树链剖分][差分] Luogu P4211 LCA

    题目描述

    给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。 有q次询问,每次询问给出l r z,求sum_{l leq i leq r}dep[LCA(i,z)]lirdep[LCA(i,z)]

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

    输入样例#1: 
    5 2
    0
    0
    1
    1
    1 4 3
    1 4 2
    输出样例#1: 
    8
    5

    说明

    共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。

    题解

    • 我们把每要询问的点往上都打上标记,然后把z点往上找到每个标记第一次出现的位置
    • 其实我们可以发现,每个标记的深度等同于它上面有多少个和它一样的标记
    • 那么我们可以把每个点到根的路径都+1,然后询问z到根的和,就是答案了 
    • 可以用树链剖分搞
    • 区间[l,r]的答案=区间[1,r]的答案-区间[1,l-1]的答案,那么我们把每个询问拆成两个,一个+,一个-

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 #include <algorithm>
     5 #define N 50010
     6 using namespace std;
     7 const int mo=201314;
     8 struct node{int p,z,id,bz;}Q[N*2];
     9 struct edge{int to,from;}e[N]; 
    10 int n,m,cnt,tot,p,t[N*3],tag[N*3],ans[N*2],head[N],size[N],son[N],w[N],top[N],fa[N];
    11 bool cmp(node x,node y) {return x.p<y.p;}
    12 void insert(int x,int y) { e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt; }
    13 void dfs(int x)
    14 {
    15     size[x]=1;
    16     for (int i=head[x];i;i=e[i].from)
    17     {
    18         dfs(e[i].to),size[x]+=size[e[i].to];
    19         if (size[e[i].to]>size[son[x]]) son[x]=e[i].to;
    20     }
    21 }
    22 void dfs1(int x,int y)
    23 {
    24     w[x]=++tot,top[x]=y;
    25     if (!son[x]) return;
    26     dfs1(son[x],y);
    27     for (int i=head[x];i;i=e[i].from) if (e[i].to!=son[x]) dfs1(e[i].to,e[i].to); 
    28 }
    29 void out(int d,int x,int len) { (t[d]+=len*x)%=mo,tag[d]+=x; }
    30 void pushdown(int d,int l,int r) 
    31 {
    32     if (tag[d]) 
    33     {
    34         int mid=l+r>>1;
    35         out(d*2,tag[d],mid-l+1),out(d*2+1,tag[d],r-mid),tag[d]=0;
    36     }
    37 } 
    38 void change(int d,int l,int r,int x,int y)
    39 {
    40     if (l==x&&r==y) { out(d,1,r-l+1); return; }
    41     int mid=l+r>>1; pushdown(d,l,r);
    42     if (y<=mid) change(d*2,l,mid,x,y);
    43     else if (x>mid) change(d*2+1,mid+1,r,x,y);
    44     else change(d*2,l,mid,x,mid),change(d*2+1,mid+1,r,mid+1,y);
    45     t[d]=(t[d*2]+t[d*2+1])%mo;
    46 }
    47 int find(int d,int l,int r,int x,int y) 
    48 {
    49     if (l==x&&r==y) return t[d];
    50     int mid=l+r>>1; pushdown(d,l,r);
    51     if (y<=mid) return find(d*2,l,mid,x,y);
    52     else if (x>mid) return find(d*2+1,mid+1,r,x,y);
    53     else return find(d*2,l,mid,x,mid)+find(d*2+1,mid+1,r,mid+1,y);
    54 }
    55 void work(int x)
    56 {
    57     int f=top[x];
    58     while (x) change(1,1,n,w[f],w[x]),x=fa[f],f=top[x];
    59 }
    60 int query(int x)
    61 {
    62     int f=top[x],ans=0;
    63     while (x) (ans+=find(1,1,n,w[f],w[x]))%=mo,x=fa[f],f=top[x];
    64     return ans;
    65 }
    66 int main()
    67 {
    68     scanf("%d%d",&n,&m);
    69     for (int i=2;i<=n;i++) scanf("%d",&fa[i]),insert(++fa[i],i);
    70     dfs(1),dfs1(1,1),tot=0;
    71     for (int i=1,l,r;i<=m;i++) scanf("%d%d%d",&l,&r,&Q[++tot].z),l++,r++,Q[tot].z++,Q[tot].p=l-1,Q[tot].id=i,Q[tot].bz=-1,Q[++tot].p=r,Q[tot].id=i,Q[tot].bz=1,Q[tot].z=Q[tot-1].z;
    72     sort(Q+1,Q+tot+1,cmp); while (!Q[p+1].p) p++;
    73     for (int i=1;i<=n;i++) 
    74     {
    75         work(i);
    76         while (Q[p+1].p==i) p++,ans[Q[p].id]+=query(Q[p].z)*Q[p].bz;    
    77     } 
    78     for (int i=1;i<=m;i++) printf("%d
    ",(ans[i]+mo)%mo);
    79 } 
  • 相关阅读:
    微信小程序开发之http到https的转化
    微信公众号实践第一弹:群发功能
    C# Modbus_TCP通讯 dll库 测试TRIO运动控制器
    C语言----循环结构2(基础篇六)
    C# 调用TRIO控制器ActiveX教程
    C语言----循环结构1(基础篇五)
    TRIO-basic指令--CAM
    C语言----流程图(基础篇四)
    C语言----选择结构(基础篇三)
    C语言----输入输出语句(基础篇二)
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11212238.html
Copyright © 2011-2022 走看看