BZOJ3626: [LNOI2014]LCA

BZOJ3626: [LNOI2014]LCA

Description

给出一个n个节点的有根树(编号为0到n-1,根节点为0)。

一个点的深度定义为这个节点到根的距离+1。

设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。

有q次询问,每次询问给出l r z,求


(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)

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

HINT

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

题解Here!

又是树上的询问,首选 树链剖分/LCT。

这题就是树链剖分+线段树+差分。

deep[i]是什么?——就是从 i 点到根有多少个点(包括 i )。

我们从整体上考虑,发现对于一个询问:l , r , z 来说,所有的 lca 都在 z 到根的路径上。

从而有一些点,它们对很多的 lca 的深度都有贡献,而这个贡献等于在这个点下面的 lca 的个数,所以我们可以把每个 lca 到根的路径上的每个点的权值都加一。

然后从 z 向上走到根,沿路统计的权值就是答案了。

就是:对于一个询问: l , r , z ,我们把每个点 i ( l <= i <= r ) 到根的路径上的每一个点的权值都加一,因为:

所有的 lca 都在 z 到根的路径上,所以我们可以从 z 点向上爬到根,沿途统计的点权值之和,就是答案了。

我们每次的操作都是从某个点到根的,所以树链剖分+线段树就好了。

但是我们每次清空线段树,然后从 l ~ r 再添加一遍,树剖+线段树的复杂度就是 n*(logn)^2 的,还要做 q 次,复杂度依然不理想。

于是想到:差分可以将询问拆开,而且每个拆开的区间之间是有重叠的,是可以转移的,而不用每次都清空。

而且差分后的数组只与右端点有关!

所以我们可以将差分后的区间按照右端点从小到大排序(左端点都是根),然后按从小到大的顺序添加点,每遇到一个询问就查询一次。

于是一波sao操作就A了。。。

附代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) b[x].data
#define SIGN(x) b[x].c
#define LSIDE(x) b[x].l
#define RSIDE(x) b[x].r
#define WIDTH(x) (RSIDE(x)-LSIDE(x)+1)
#define MAXN 50010
#define MOD 201314
using namespace std;
int n,m,c=1,d=1,e=1;
int head[MAXN],deep[MAXN],fa[MAXN],son[MAXN],size[MAXN],id[MAXN],top[MAXN];
struct node1{
    int next,to;
}a[MAXN];
struct node2{
    int data,c,l,r;
}b[MAXN<<2];
struct node3{
    int x,u,id;
    bool flag;
}que[MAXN<<1];
struct node4{
    int l,r;
}ans[MAXN];
inline int read(){
    int date=0,w=1;char c=0;
    while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    return date*w;
}
bool cmp(const node3 &x,const node3 &y){
    if(x.x==y.x)return x.id<y.id;
    return x.x<y.x;
}
inline void add(int x,int y){
    a[c].to=y;
    a[c].next=head[x];
    head[x]=c++;
}
inline void addque(int l,int r,int u,int i){
    que[e].x=l;que[e].u=u;que[e].id=i;
    que[e++].flag=false;
    que[e].x=r;que[e].u=u;que[e].id=i;
    que[e++].flag=true;
}
void dfs1(int rt){
    son[rt]=0;size[rt]=1;
    for(int i=head[rt];i;i=a[i].next){
        int will=a[i].to;
        if(!deep[will]){
            deep[will]=deep[rt]+1;
            fa[will]=rt;
            dfs1(will);
            size[rt]+=size[will];
            if(size[son[rt]]<size[will])son[rt]=will;
        }
    }
}
void dfs2(int rt,int f){
    id[rt]=d++;top[rt]=f;
    if(son[rt])dfs2(son[rt],f);
    for(int i=head[rt];i;i=a[i].next){
        int will=a[i].to;
        if(will!=fa[rt]&&will!=son[rt])
        dfs2(will,will);
    }
}
inline void pushup(int rt){
    DATA(rt)=(DATA(LSON)+DATA(RSON))%MOD;
}
inline void pushdown(int rt){
    if(!SIGN(rt)||LSIDE(rt)==RSIDE(rt))return;
    SIGN(LSON)=(SIGN(LSON)+SIGN(rt))%MOD;
    DATA(LSON)=(DATA(LSON)+SIGN(rt)*WIDTH(LSON))%MOD;
    SIGN(RSON)=(SIGN(RSON)+SIGN(rt))%MOD;
    DATA(RSON)=(DATA(RSON)+SIGN(rt)*WIDTH(RSON))%MOD;
    SIGN(rt)=0;
}
void buildtree(int l,int r,int rt){
    int mid;
    LSIDE(rt)=l;
    RSIDE(rt)=r;
    if(l==r){
        DATA(rt)=0;
        return;
    }
    mid=l+r>>1;
    buildtree(l,mid,LSON);
    buildtree(mid+1,r,RSON);
    pushup(rt);
}
void update(int l,int r,int c,int rt){
    int mid;
    if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
        SIGN(rt)=(SIGN(rt)+c)%MOD;
        DATA(rt)=(DATA(rt)+c*WIDTH(rt))%MOD;
        return;
    }
    pushdown(rt);
    mid=LSIDE(rt)+RSIDE(rt)>>1;
    if(l<=mid)update(l,r,c,LSON);
    if(mid<r)update(l,r,c,RSON);
    pushup(rt);
}
int query(int l,int r,int rt){
    int mid,ans=0;
    if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt);
    pushdown(rt);
    mid=LSIDE(rt)+RSIDE(rt)>>1;
    if(l<=mid)ans=(ans+query(l,r,LSON)%MOD)%MOD;
    if(mid<r)ans=(ans+query(l,r,RSON)%MOD)%MOD;
    return ans%MOD;
}
void work_update(int x,int y,int k){
    while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]])swap(x,y);
        update(id[top[x]],id[x],1,1);
        x=fa[top[x]];
    }
    if(deep[x]>deep[y])swap(x,y);
    update(id[x],id[y],1,1);
    return;
}
int work_query(int x,int y){
    int s=0;
    while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]])swap(x,y);
        s=(s+query(id[top[x]],id[x],1)%MOD)%MOD;
        x=fa[top[x]];
    }
    if(deep[x]>deep[y])swap(x,y);
    s=(s+query(id[x],id[y],1)%MOD)%MOD;
    return s;
}
void work(){
    int now=1,id;
    for(int i=1;i<e;i++){
        while(now<=que[i].x){
            work_update(1,now,1);
            now++;
        }
        id=que[i].id;
        if(que[i].flag)ans[id].r=work_query(1,que[i].u);
        else ans[id].l=work_query(1,que[i].u);
    }
    for(int i=1;i<=m;i++)printf("%d\n",(ans[i].r-ans[i].l+MOD)%MOD);
}
void init(){
    int x,l,r,u;
    n=read();m=read();
    for(int i=2;i<=n;i++){
        x=read()+1;
        add(x,i);
    }
    deep[1]=1;
    dfs1(1);
    dfs2(1,1);
    buildtree(1,n,1);
    for(int i=1;i<=m;i++){
        l=read();r=read()+1;u=read()+1;
        addque(l,r,u,i);
    }
    sort(que+1,que+e,cmp);
}
int main(){
    init();
    work();
    return 0;
}

 

posted @   符拉迪沃斯托克  阅读(204)  评论(0)    收藏  举报
编辑推荐:
· dotnet 9 通过 AppHostRelativeDotNet 指定自定义的运行时路径
· 如何统计不同电话号码的个数?—位图法
· C#高性能开发之类型系统:从 C# 7.0 到 C# 14 的类型系统演进全景
· 从零实现富文本编辑器#3-基于Delta的线性数据结构模型
· 记一次 .NET某旅行社酒店管理系统 卡死分析
阅读排行:
· 用c#从头写一个AI agent,实现企业内部自然语言数据统计分析
· 三维装箱问题(3D Bin Packing Problem, 3D-BPP)
· Windows上,10分钟构建一个本地知识库
· 使用 AOT 编译保护 .NET 核心逻辑,同时支持第三方扩展
· Java虚拟机代码是如何一步一步变复杂且难以理解的?
Live2D
欢迎阅读『BZOJ3626: [LNOI2014]LCA』
点击右上角即可分享
微信分享提示