[火星补锅] 非确定性有穷状态决策自动机练习题Vol.3 T3 && luogu P4211 [LNOI2014]LCA 题解
前言:
这题感觉还是很有意思。离线思路很奇妙。可能和二次离线有那么一点点相似?当然我不会二次离线我就不云了。
解析:
题目十分清真。
求一段连续区间内的所有点和某个给出的点的Lca的深度和。
首先可以转化一步。
我们可以只考虑一个询问。那么当前询问的答案可以转化为:将区间[l,r]中的每一个点到根节点的路径上的点的点权都加一。然后统计给出点z到根节点的路径上的点权之和即可。
可以使用树剖线段树搞定。
这个转化正确性显然。
但是,当考虑到多次询问时,就有点不对劲。因为两个询问如果一起计算贡献,就会算重。
比如,考虑[1,6]和[4,7],如果先算[1,6],那当算[4,7]时,就要先把之前线段树内的答案清空,再计算这个区间的答案。
相当于每一次询问都要清空线段树,然后重新计算。这样显然T的飞起。
那怎样才能利用之前询问的信息呢?
首先容易想到,计算一段区间的贡献,可以转化为求两个前缀的贡献之差。
然后,我们可以发现,如果计算当前区间的答案时,想使用上个区间的答案,当且仅当当前区间包含上一个区间。
那我们就可以设计出一个合理的顺序,使每个区间都能够包含之前的区间。
现在就很清晰了。
首先我们把所有询问离线下来,然后把每个询问[l,r]拆成两个区间[1,l-1]和[1,r],按照右端点从小到大排序。最后统计答案。
然后就没啥了。注意细节。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
const int maxn=50000+10,mod=201314;
#define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++)
#define read() ({ register int x = 0, f = 1; register char c = gc(); while(c < '0' || c > '9') { if (c == '-') f = -1; c = gc();} while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc(); f * x; })
char buf[1 << 20], *p1, *p2;
struct Segment_tree{
ll val,lazy;
}tree[maxn<<2];
struct node{
int to,nxt;
}edge[maxn<<1];
struct que{
int r,z,op,data;
ll ans;
que(){}
que(int x,int y,int c,int d){
r=x;
z=y;
op=c;
data=d;
}
}b[maxn<<1];
int head[maxn],depth[maxn],size[maxn],son[maxn],fa[maxn],dfn[maxn],top[maxn];
int Time,cnt,n,m,tot;
void add(int from,int to){
edge[++cnt].to=to;
edge[cnt].nxt=head[from];
head[from]=cnt;
}
void dfs1(int u){
size[u]=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v==fa[u]) continue;
depth[v]=depth[u]+1;
dfs1(v);
size[u]+=size[v];
if(size[v]>size[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t){
top[u]=t;
dfn[u]=++Time;
if(son[u]) dfs2(son[u],t);
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
bool cmp(que x,que y){
return x.r<y.r ;
}
bool cmp2(que x,que y){
return x.data!=y.data ? x.data<y.data : x.op<y.op ;
}
void pushup(int rt){
tree[rt].val=(tree[rt<<1].val+tree[rt<<1|1].val)%mod;
}
void update(int rt,int l,int r,ll x){
tree[rt].lazy+=x;
if(tree[rt].lazy>=mod) tree[rt].lazy-=mod;
tree[rt].val+=x*(r-l+1)%mod;
if(tree[rt].val>=mod) tree[rt].val-=mod;
}
void pushdown(int rt,int l,int r){
if(!tree[rt].lazy) return;
int mid=(l+r)>>1;
update(rt<<1,l,mid,tree[rt].lazy);
update(rt<<1|1,mid+1,r,tree[rt].lazy);
tree[rt].lazy=0;
}
void modify(int rt,int l,int r,int s,int t){
if(s<=l&&r<=t){
update(rt,l,r,1);
return;
}
int mid=(l+r)>>1;
pushdown(rt,l,r);
if(s<=mid) modify(rt<<1,l,mid,s,t);
if(t>mid) modify(rt<<1|1,mid+1,r,s,t);
pushup(rt);
}
ll query(int rt,int l,int r,int s,int t){
if(s<=l&&r<=t) return tree[rt].val%mod;
int mid=(l+r)>>1;
pushdown(rt,l,r);
if(t<=mid) return query(rt<<1,l,mid,s,t);
if(s>mid) return query(rt<<1|1,mid+1,r,s,t);
return (query(rt<<1,l,mid,s,t)+query(rt<<1|1,mid+1,r,s,t))%mod;
}
void Modify(int u){
while(top[u]!=1){
modify(1,1,n,dfn[top[u]],dfn[u]);
u=fa[top[u]];
}
modify(1,1,n,1,dfn[u]);
}
ll Query(int u){
ll res=0;
while(top[u]!=1){
res+=query(1,1,n,dfn[top[u]],dfn[u]);
if(res>=mod) res-=mod;
u=fa[top[u]];
}
res+=query(1,1,n,1,dfn[u]);
if(res>=mod) res-=mod;
return res;
}
void Solve(){
scanf("%lld%lld",&n,&m);
for(int i=2;i<=n;++i){
scanf("%lld",&fa[i]);
fa[i]++;
add(i,fa[i]);
add(fa[i],i);
}
dfs1(1);
dfs2(1,1);
for(int i=1,aa,bb,cc;i<=m;++i){
scanf("%lld%lld%lld",&aa,&bb,&cc);
aa++;bb++;cc++;
b[++tot]=que(aa-1,cc,0,i);
b[++tot]=que(bb,cc,1,i);
}
sort(b+1,b+tot+1,cmp);
int now=0;
for(int i=1;i<=tot;++i){
while(now<b[i].r){
now++;
Modify(now);
}
b[i].ans=Query(b[i].z);
}
sort(b+1,b+tot+1,cmp2);
for(int i=2;i<=tot;i+=2) printf("%lld\n",(b[i].ans-b[i-1].ans+mod)%mod);
}
signed main(){
Solve();
return 0;
}
[火星补锅] 非确定性有穷状态决策自动机练习题Vol.3 T3 && luogu P4211 [LNOI2014]LCA 题解的更多相关文章
- [火星补锅] 非确定性有穷状态决策自动机练习题Vol.1 T3 第K大区间 题解
前言: 老火星人了 解析: 很妙的二分题.如果没想到二分答案.. 很容易想到尝试用双指针扫一下,看看能不能统计答案. 首先,tail指针右移时很好处理,因为tail指针右移对区间最大值的影响之可能作用 ...
- 非确定性有穷状态决策自动机练习题Vol.1 A.扭动的回文串
非确定性有穷状态决策自动机练习题Vol.1 A.扭动的回文串 题目描述 \(JYY\)有两个长度均为\(N\)的字符串\(A\)和\(B\). 一个"扭动字符串\(S(i,j,k)\)由\( ...
- 非确定性有穷状态决策自动机练习题Vol.2 C. 奇袭
非确定性有穷状态决策自动机练习题Vol.2 C. 奇袭 题目描述 由于各种原因,桐人现在被困在\(Under World\)(以下简称\(UW\))中,而\(UW\)马上 要迎来最终的压力测试--魔界 ...
- 非确定性有穷状态决策自动机练习题Vol.3 D. Dp搬运工3
非确定性有穷状态决策自动机练习题Vol.3 D. Dp搬运工3 题目描述 给定两个长度为 \(n\) 的排列,定义 \(magic(A,B)=∑_{i=1}^nmax(Ai,Bi)\) . 现在给定 ...
- [火星补锅] 水题大战Vol.2 T2 && luogu P3623 [APIO2008]免费道路 题解
前言: 如果我自己写的话,或许能想出来正解,但是多半会因为整不出正确性而弃掉. 解析: 这题算是对Kruskal的熟练运用吧. 要求一颗生成树.也就是说,最后的边数是确定的. 首先我们容易想到一个策略 ...
- [火星补锅] 水题大战Vol.2 T1 && luogu P1904 天际线 题解 (线段树)
前言: 当时考场上并没有想出来...后来也是看了题解才明白 解析: 大家(除了我)都知道,奇点和偶点会成对出现,而出现的前提就是建筑的高度突然发生变化.(这个性质挺重要的,我之前没看出来) 所以就可以 ...
- [火星补锅] siano 神奇的线段树
前言: 本来以为很难打的,没想到主干一次就打对了,然而把输入的b和d弄混了,这sb错误调了两个小时... 解析: 神奇的线段树.注意到有一个性质,无论怎么割草,生长速度快的一定不会比生长速度慢的矮.因 ...
- P1364 医院设置 (补锅,memset初始化较大值不可用0x7fffffff )
P1364 医院设置 题解 弗洛伊德水过 注意初始化一个大数 0x3f 可以,0x5f 好像也可以,但是0x7fffffff 我是真的炸了,初始化为-1 (后面补锅有详细解释) 代码 #include ...
- goroutine 分析 协程的调度和执行顺序 并发写 run in the same address space 内存地址 闭包 存在两种并发 确定性 非确定性的 Go 的协程和通道理所当然的支持确定性的并发方式(
package main import ( "fmt" "runtime" "sync" ) const N = 26 func main( ...
随机推荐
- 记一次 .NET 某桌面奇侠游戏 非托管内存泄漏分析
一:背景 1. 讲故事 说实话,这篇dump我本来是不准备上一篇文章来解读的,但它有两点深深的感动了我. 无数次的听说用 Unity 可做游戏开发,但百闻不如一见. 游戏中有很多金庸武侠小说才有的名字 ...
- Python树莓派 爬虫心得
平台: 树莓派 linux 语言:python 搞一个爬虫都清楚是怎么回事,我这里玩过之后有下面的心得: 为什么要用树莓派呢,省电啊,没乱七八糟的桌面问题,可以一直开着. 1.树莓派上的磁盘写入对于不 ...
- PHP7兼容mysql_connect的方法
在php7版本的时候,mysql_connect已经不再被支持了,本文将讲述在代码层面实现php7兼容mysql系列,mysql_connect等操作. PHP7不再兼容mysql系列函数,入mysq ...
- jquery动态生成dom(比如append)导致js事件无效
如果无效用这个方法: on() 方法在被选元素及子元素上添加一个或多个事件处理程序. <div id="zkdiv"> <input type="bu ...
- 根据类拼凑成url参数
/// <summary> /// 根据类拼凑成url参数 /// </summary> /// <typeparam name ...
- Shell系列(12)- 预定义变量(5)
预定义变量 作用 $? 常用:最后一次执行的命令的返回状态. 如果这个变量的值为0,证明上一个命令正确执行:如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了 $$ ...
- MYSQL分页 limit 太慢优化
limit分页原理 当我们翻到最后几页时,查询的sql通常是:select * from table where column=xxx order by xxx limit 1000000,20.查询 ...
- LR集合点策略
给大家分享一个LR集合点策略,跑并发脚本时,一定要设置策略,要不然得出的响应时间无意义.默认选择第一个(当所有虚拟用户中的x % 到达集合点进释放,即仅当指定百分比的虚拟用户到达集合点时,才释放虚拟用 ...
- Loj#2880-「JOISC 2014 Day3」稻草人【CDQ分治,单调栈,二分】
正题 题目链接:https://loj.ac/problem/2880 题目大意 给出平面上的\(n\)个点,然后求有多少个矩形满足 左下角和右上角各有一个点 矩形之间没有其他点 \(1\leq n\ ...
- Java MD5和SHA256等常用加密算法
前言 我们在做java项目开发的时候,在前后端接口分离模式下,接口信息需要加密处理,做签名认证,还有在用户登录信息密码等也都需要数据加密.信息加密是现在几乎所有项目都需要用到的技术,身份认证.单点登陆 ...