【LOJ】#2558. 「LNOI2014」LCA
题解
当年LN还是有专门的省选题的,但是还不如没有
看到这道题,我就想到了一个清晰易懂,简单好写,代码优美的树链剖分线段树套主席树的\(O(q\log^{3}n)\)做法,且就5组数据出题人肯定是不会出题树剖卡不到上限……
但是我太菜了,我并不想实现这个算法……然后看了看一个神奇的\(O(n \log^{2} n)\)离线做法
我们注意到,实际上所求就是z到根节点路径上,每个点子树里的点下标在[l,r]的有多少个的和
首先区间都是可以拆成前缀和加减的,然后我们离线,往树链剖分加入每个节点,然后对于询问拆成两个前缀和的询问,排序依次查询回答即可
吐槽
1.模数没有任何意义,只是为了秀,还让人注意不到
2.我数组开小了,gg
代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
//#define ivorysi
#define pb push_back
#define MAXN 50005
#define space putchar(' ')
#define enter putchar('\n')
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) putchar('-'),x = -x;
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
const int MOD = 201314;
struct node {
int to,next;
}E[MAXN * 2];
struct qry {
int id,on,pos,z;
friend bool operator < (const qry &a,const qry &b) {
return a.pos < b.pos;
}
}Qry[MAXN * 2];
int head[MAXN],sumE,N,Q,siz[MAXN],top[MAXN],son[MAXN],fa[MAXN],dfn[MAXN],tot;
int ans[MAXN],tr[MAXN * 4],lz[MAXN * 4];
void add(int u,int v) {
E[++sumE].to = v;
E[sumE].next = head[u];
head[u] = sumE;
}
void dfs1(int u) {
siz[u]++;
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u]) {
fa[v] = u;
dfs1(v);
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
}
void dfs2(int u) {
dfn[u] = ++tot;
if(!top[u]) top[u] = u;
if(son[u]) {top[son[u]] = top[u];dfs2(son[u]);}
for(int i = head[u] ; i ; i = E[i].next) {
int v = E[i].to;
if(v != fa[u] && v != son[u]) dfs2(v);
}
}
void addlazy(int u,int L,int R,int v) {
tr[u] = (tr[u] + (R - L + 1) * v) % MOD;lz[u] = lz[u] + v;
}
void push_down(int u,int L,int R) {
int mid = (L + R) >> 1;
if(lz[u]) {
addlazy(u << 1,L,mid,lz[u]);
addlazy(u << 1 | 1,mid + 1,R,lz[u]);
lz[u] = 0;
}
}
void Add(int u,int L,int R,int l,int r,int v) {
if(L == l && R == r) {addlazy(u,L,R,v);return;}
int mid = (L + R) >> 1;
push_down(u,L,R);
if(r <= mid) Add(u << 1,L,mid,l,r,v);
else if(l > mid) Add(u << 1 | 1,mid + 1,R,l,r,v);
else Add(u << 1,L,mid,l,mid,v),Add(u << 1 | 1,mid + 1,R,mid + 1,r,v);
tr[u] = (tr[u << 1] + tr[u << 1 | 1]) % MOD;
}
int Query(int u,int L,int R,int l,int r) {
if(L == l && R == r) return tr[u];
push_down(u,L,R);
int mid = (L + R) >> 1;
if(r <= mid) return Query(u << 1,L,mid,l,r);
else if(l > mid) return Query(u << 1 | 1,mid + 1,R,l,r);
else return Query(u << 1,L,mid,l,mid) + Query(u << 1 | 1,mid + 1,R,mid + 1,r);
}
void Init() {
read(N);read(Q);
for(int i = 2 ; i <= N ; ++i) {
int f;read(f);++f;
add(i,f);add(f,i);
}
int l,r,z;
for(int i = 1 ; i <= Q ; ++i) {
read(l);read(r);read(z);++l;++r;++z;
Qry[i * 2 - 1].id = i;Qry[i * 2 - 1].on = -1;Qry[i * 2 - 1].pos = l - 1;Qry[i * 2 - 1].z = z;
Qry[i * 2].id = i;Qry[i * 2].on = 1;Qry[i * 2].pos = r;Qry[i * 2].z = z;
}
sort(Qry + 1,Qry + 2 * Q + 1);
dfs1(1);
dfs2(1);
}
void Insert(int x) {
while(top[x] != 1) {
Add(1,1,N,dfn[top[x]],dfn[x],1);
x = fa[top[x]];
}
Add(1,1,N,dfn[top[x]],dfn[x],1);
}
int Query(int x) {
int res = 0;
while(top[x] != 1) {
res += Query(1,1,N,dfn[top[x]],dfn[x]) % MOD;
x = fa[top[x]];
}
res += Query(1,1,N,dfn[top[x]],dfn[x]);
return res % MOD;
}
void Solve() {
int p = 1;
while(Qry[p].pos < 1) ++p;
for(int i = 1 ; i <= N ; ++i) {
Insert(i);
while(Qry[p].pos == i) {
ans[Qry[p].id] += Qry[p].on * Query(Qry[p].z) % MOD;
++p;
}
}
for(int i = 1 ; i <= Q ; ++i) {
ans[i] = (ans[i] % MOD + MOD) % MOD;
out(ans[i]);enter;
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
return 0;
}
【LOJ】#2558. 「LNOI2014」LCA的更多相关文章
- 【LOJ】#3046. 「ZJOI2019」语言
LOJ#3046. 「ZJOI2019」语言 先orz zsy吧 有一个\(n\log^3n\)的做法是把树链剖分后,形成logn个区间,这些区间两两搭配可以获得一个矩形,求矩形面积并 然后就是对于一 ...
- 【LOJ】#2210. 「HNOI2014」江南乐
LOJ#2210. 「HNOI2014」江南乐 感觉是要推sg函数 发现\(\lfloor \frac{N}{i}\rfloor\)只有\(O(\sqrt{N})\)种取值 考虑把这些取值都拿出来,能 ...
- 【LOJ】#3098. 「SNOI2019」纸牌
LOJ#3098. 「SNOI2019」纸牌 显然选三个以上的连续牌可以把他们拆分成三个三张相等的 于是可以压\((j,k)\)为有\(j\)个连续两个的,有\(k\)个连续一个的 如果当前有\(i\ ...
- 【LOJ】#3103. 「JSOI2019」节日庆典
LOJ#3103. 「JSOI2019」节日庆典 能当最小位置的值一定是一个最小后缀,而有用的最小后缀不超过\(\log n\)个 为什么不超过\(\log n\)个,看了一下zsy的博客.. 假如\ ...
- 【LOJ】#3102. 「JSOI2019」神经网络
LOJ#3102. 「JSOI2019」神经网络 首先我们容易发现就是把树拆成若干条链,然后要求这些链排在一个环上,同一棵树的链不相邻 把树拆成链可以用一个简单(但是需要复杂的分类讨论)的树背包实现 ...
- 【LOJ】#3101. 「JSOI2019」精准预测
LOJ#3101. 「JSOI2019」精准预测 设0是生,1是死,按2-sat连边那么第一种情况是\((t,x,1) \rightarrow (t + 1,y,1)\),\((t + 1,y, 0) ...
- 【LOJ】#3097. 「SNOI2019」通信
LOJ#3097. 「SNOI2019」通信 费用流,有点玄妙 显然按照最小路径覆盖那题的建图思路,把一个点拆成两种点,一种是从这个点出去,标成\(x_{i}\),一种是输入到这个点,使得两条路径合成 ...
- 【LOJ】#3096. 「SNOI2019」数论
LOJ#3096. 「SNOI2019」数论 如果\(P > Q\)我们把\(P\)和\(Q\)换一下,现在默认\(P < Q\) 这个时候每个合法的\(a_i\)都可以直接落到\(Q\) ...
- 【LOJ】#2239. 「CQOI2014」危桥
LOJ#2239. 「CQOI2014」危桥 就是先把每条边正着连一条容量为2的边,反着连一条容量为2的边 显然如果只有一个人走的话,答案就是一个源点往起点连一条容量为次数×2的边,终点往汇点连一个次 ...
随机推荐
- 豪迈开料锯MDB文件分析
豪迈CuteRite(简称CR)优化板件后会生成SAW文件.MDB文件,SAW文件用于开料机开料,MDB文件中保存了有限的优化结果记录. 因为CR软件可以根据配置生成不同结构的mdb文件,所以以下内容 ...
- angularJS__v1.5.6点击同一个菜单刷新
针对angularjs的1.0版本,点击菜单不刷新问题,只需在配置路由时,路由路径添加“/”,如,点击 标签时,就会刷新,
- HDU 5985 概率
n种硬币各有cnt[i]枚,每轮下其有p[i]概率保留,问各种硬币只有它存活到最后一轮的概率. 设k轮后i硬币存活概率$a[i][k]=(1-p^k_i)^{cnt[i]}$ 则最后只有第i种硬币存活 ...
- 华为mate 10 pro安装失败,提示没有未包含任何证书
原因: Android 7.0 引入一项新的应用签名方案 APK Signature Scheme v2,它能提供更快的应用安装时间和更多针对未授权 APK 文件更改的保护.在默认情况下,Androi ...
- Javascript实现返回上一页面并刷新
今天写了一个小小的提示成功的页面,同时要求返回上一页面,并实现对上一页面的操作进行刷新(例如删除的,添加的),在网上搜寻了一遍,基本上90%的都是说的是用window.history.go(-1), ...
- SpringCloud微服务简介(一)
Spring Cloud简单认识 微服务英文名称Microservice,Microservice架构模式就是将整个Web应用组织为一系列小的Web服务.这些小的Web服务可以独立地编译及部署,并通过 ...
- Linux学习5-线程
线程 1.1什么是线程? 在一个程序中的多个执行路线就叫做线程(thread).更准确的定义是:线程是一个进程内部的一个控制序列. 要搞清楚fork系统调用和创建新线程之间的区别.当进程执行for ...
- 【leetcode 简单】 第九十三题 二进制手表
二进制手表顶部有 4 个 LED 代表小时(0-11),底部的 6 个 LED 代表分钟(0-59). 每个 LED 代表一个 0 或 1,最低位在右侧. 例如,上面的二进制手表读取 “3:25”. ...
- 支付宝hr终面,忐忑的等待结果
上周一,内推网投了支付宝上海的 高级java软件开发工程师:阿里效率就是高,不到30分钟电话就过来了!约的上周五14:00面试:上周五技术面了2轮,第一轮是主管面试,貌似给了p6;第二轮部门总监面试, ...
- 【多视图几何】TUM 课程 第3章 透视投影
课程的 YouTube 地址为:https://www.youtube.com/playlist?list=PLTBdjV_4f-EJn6udZ34tht9EVIW7lbeo4 .视频评论区可以找到课 ...