【[LNOI2014]LCA】
这题好神啊
能够\(1A\)真是不可思议
首先看到要求的这个柿子\(\sum_{i=l}^{r}deep[LCA(i,z)]\),而且\(l\)和\(r\)并不是来自与一棵子树或者一条链,而是编号连续的一段
所以肯定没有什么办法可以一下子求出来这么多的\(LCA\)的
得想个好的办法转化一下
于是就想往主席树上想
首先\(z\)的\(lca\)肯定是在\(z\)到根的路径上的,于是我们可以定住\(lca\),来求这个\(lca\)对答案的贡献
于是我们有一个主席树的暴力
我们就枚举\(z\)到根的路径上的点,对于这些每一个点,我们求出在其子树内部有多少个大于\(l\)小于\(r\)的点,乘上深度,这就是这个\(lca\)的贡献
吗?
显然不是,我们得减去那些在下面的那些子树里就已经算过了的数
所以我们会暴力啦,真开心
那我们想一下如何优化暴力
先来看看答案长什么样子
好吧,我画的还是很难看,这可是魏佬钦定
我们设\(sum_i\)表示在\(i\)的子树内部有多少个符合条件的点
于是我们的答案可以写成
\]
之后就会惊奇的发现答案竟然就是\(sum_4+sum_3+sum_2+sum_1\)
那我们怎么维护啊,难道要硬上主席树?
显然不用啊
既然没有强制在线,我们就离线+树剖呗
一个点显然只会对他本身到根上这条路径的点产生贡献,于是就是一个树剖板子了
同时查询也是一个简单的根路径查询
至于如何统计答案,我们将询问排序,之后可以将插入顺序想象成时间轴,于是就可以差分求解了
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define re register
#define maxn 50005
const int mod=201314;
struct E
{
int v,nxt;
}e[maxn<<1];
struct Ask
{
int x,y,z,rk;
}a[maxn];
int n,m,num,Q,cnt;
int top[maxn],deep[maxn],fa[maxn],to[maxn],sum[maxn],son[maxn],head[maxn];
int l[maxn<<2],r[maxn<<2],tag[maxn<<2],d[maxn<<2];
int Lans[maxn],Rans[maxn];
inline void add_edge(int x,int y)
{
e[++num].v=y;
e[num].nxt=head[x];
head[x]=num;
}
inline int read()
{
char c=getchar();
int x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x;
}
void build(int x,int y,int i)
{
l[i]=x,r[i]=y,d[i]=0,tag[i]=0;
if(x==y) return;
int mid=x+y>>1;
build(x,mid,i<<1),build(mid+1,y,i<<1|1);
}
inline void pushdown(int i)
{
if(!tag[i]) return;
tag[i<<1]+=tag[i];
if(tag[i<<1]>mod) tag[i<<1]%=mod;
tag[i<<1|1]+=tag[i];
if(tag[i<<1|1]>mod) tag[i<<1|1]%=mod;
d[i<<1]+=(r[i<<1]-l[i<<1]+1)*tag[i];
d[i<<1]%=mod;
d[i<<1|1]+=(r[i<<1|1]-l[i<<1|1]+1)*tag[i];
d[i<<1|1]%=mod;
tag[i]=0;
}
void change(int x,int y,int i)
{
if(x<=l[i]&&y>=r[i])
{
tag[i]++;
d[i]+=r[i]-l[i]+1;
if(d[i]>mod) d[i]%=mod;
return;
}
pushdown(i);
int mid=l[i]+r[i]>>1;
if(y<=mid) change(x,y,i<<1);
else if(x>mid) change(x,y,i<<1|1);
else change(x,y,i<<1),change(x,y,i<<1|1);
d[i]=(d[i<<1]+d[i<<1|1])%mod;
}
int query(int x,int y,int i)
{
if(x<=l[i]&&y>=r[i]) return d[i];
pushdown(i);
int mid=l[i]+r[i]>>1;
if(y<=mid) return query(x,y,i<<1);
if(x>mid) return query(x,y,i<<1|1);
return (query(x,y,i<<1)+query(x,y,i<<1|1))%mod;
}
void dfs1(int x)
{
sum[x]=1;
int maxx=-1;
for(re int i=head[x];i;i=e[i].nxt)
if(!deep[e[i].v])
{
deep[e[i].v]=deep[x]+1;
fa[e[i].v]=x;
dfs1(e[i].v);
sum[x]+=sum[e[i].v];
if(sum[e[i].v]>maxx) maxx=sum[e[i].v],son[x]=e[i].v;
}
}
void dfs2(int x,int topf)
{
top[x]=topf;
to[x]=++cnt;
if(!son[x]) return;
dfs2(son[x],topf);
for(re int i=head[x];i;i=e[i].nxt)
if(deep[e[i].v]>deep[x]&&son[x]!=e[i].v) dfs2(e[i].v,e[i].v);
}
inline void tree_change(int x,int y)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) std::swap(x,y);
change(to[top[x]],to[x],1);
x=fa[top[x]];
}
if(deep[x]>deep[y]) std::swap(x,y);
change(to[x],to[y],1);
}
inline int tree_query(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) std::swap(x,y);
ans+=query(to[top[x]],to[x],1);
if(ans>mod) ans%=mod;
x=fa[top[x]];
}
if(deep[x]>deep[y]) std::swap(x,y);
ans+=query(to[x],to[y],1);
return ans%mod;
}
inline int cmp(Ask K,Ask M)
{
return K.x<M.x;
}
inline int cop(Ask K,Ask M)
{
return K.y<M.y;
}
int main()
{
n=read(),Q=read();
int Fa;
for(re int i=1;i<n;i++)
Fa=read(),add_edge(Fa,i);
deep[0]=1;
dfs1(0);
dfs2(0,0);
build(1,n,1);
for(re int i=1;i<=Q;i++)
a[i].x=read(),a[i].y=read(),a[i].z=read(),a[i].rk=i;
std::sort(a+1,a+Q+1,cmp);
int tot=1;
for(re int i=-1;i<n;i++)
{
if(i>=0) tree_change(i,0);
while(a[tot].x-1==i)
{
Lans[a[tot].rk]=tree_query(a[tot].z,0);
tot++;
}
}
build(1,n,1);
std::sort(a+1,a+Q+1,cop);
tot=1;
for(re int i=0;i<n;i++)
{
tree_change(i,0);
while(a[tot].y==i)
{
Rans[a[tot].rk]=tree_query(a[tot].z,0);
tot++;
}
}
for(re int i=1;i<=Q;i++)
printf("%d\n",(Rans[i]-Lans[i]+mod)%mod);
return 0;
}
【[LNOI2014]LCA】的更多相关文章
- [SPOJ913]QTREE2 - Query on a tree II【倍增LCA】
题目描述 [传送门] 题目大意 给一棵树,有两种操作: 求(u,v)路径的距离. 求以u为起点,v为终点的第k的节点. 分析 比较简单的倍增LCA模板题. 首先对于第一问,我们只需要预处理出根节点到各 ...
- 【Tarjan,LCA】【3-21个人赛】【problemD】
Problem D Time Limit : 6000/3000ms (Java/Other) Memory Limit : 65535/32768K (Java/Other) Total Sub ...
- POJ3694 Network【连通分量+LCA】
题意: 一个无向图可以有重边,下面q个操作,每次在两个点间连接一条有向边,每次连接后整个无向图还剩下多少桥(注意是要考虑之前连了的边,每次回答是在上一次的基础之上). 思路: 首先运行一次Tarjan ...
- 【最小生成树+LCA】Imperial roads
http://codeforces.com/gym/101889 I 先跑一遍最小生成树,把经过的边和答案记录下来 对于每个询问的边,显然如果处于MST中,答案不变 如果不在MST中,假设这条边连上了 ...
- 【Targan+LCA】HDU 3686 Traffic Real Time Query
题目内容 洛谷链接 给出一个\(n\)个节点,\(m\)条边的无向图和两个节点\(s\)和\(t\),问这两个节点的路径中有几个点必须经过. 输入格式 第一行是\(n\)和\(m\). 接下来\(m\ ...
- 【BZOJ3626】[LNOI2014]LCA 离线+树链剖分+线段树
[BZOJ3626][LNOI2014]LCA Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度 ...
- bzoj3626【LNOI2014】LCA
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MB Submit: 1266 Solved: 448 [Submit][Stat ...
- 【POJ 3694】 Network(割边<桥>+LCA)
[POJ 3694] Network(割边+LCA) Network Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 7971 ...
- 【LCA】BZOJ1776-[Usaco2010 Hol]cowpol 奶牛政坛
[题目大意] 一棵n个点的树,树上每个点属于一个党派,要求每个党派的最远距离点.两点间距离为两点间边的个数. [思路] yy一下可知,最远距离点中必有一个是该党派深度最深的一个,那么我们就记下最深的点 ...
随机推荐
- [Linux]C语言Linux系统编程创建进程
1.进程ID 每一个进程都由一个唯一的标识符表示,即进程ID,简称pid.系统保证在某时刻每个pid都是唯一的. 1.1分配进程ID 缺省情况下,内核将进程ID的最大值限制为32768,可以在此处设置 ...
- 撩课-Mysql详解第3部分sql分类
学习地址:[撩课-JavaWeb系列1之基础语法-前端基础][撩课-JavaWeb系列2之XML][撩课-JavaWeb系列3之MySQL][撩课-JavaWeb系列4之JDBC][撩课-JavaWe ...
- 从MySQL到ORM(三):连接、存储过程和用户权限
一.联结表 数据仍使用前文中的数据. 1.子查询 作为子查询的SELECT语句只能查询单个列.企图检索多个列将返回错误. -- 作为查询条件使用 -- 查看TNT2订单对应的客户ip(order表) ...
- 牛客Wannafly挑战赛23F 计数(循环卷积+拉格朗日插值/单位根反演)
传送门 直接的想法就是设 \(x^k\) 为边权,矩阵树定理一波后取出 \(x^{nk}\) 的系数即可 也就是求出模 \(x^k\) 意义下的循环卷积的常数项 考虑插值出最后多项式,类比 \(DFT ...
- 13 Reasons Why You Should Pay Attention to Mobile Web Performance
Mobile is no longer on the sidelines. If you’re not already thinking mobile first, you should at lea ...
- vue-router初涉
概念: vue-router: vue官方路由插件. 路由: 指单页面应用的路径管理系统.在vue中都是单页应用,相当于只有一个index.html页面,所以无法使用<a>标签,我们使用路 ...
- redux-devtools的使用
1.浏览器里安装redux-devtools 2.在项目的入口文件里 找到 createStore函数调用的地方,给它加第二个参数 window.__REDUX_DEVTOOLS_EXTENSION ...
- Git简介、安装与配置
老规矩QAQ,先来简单介绍一下Git: Git是一个分布式版本控制系统,可以理解为是一个用于管理代码,控制版本,方便多人合作开发的一款工具. Git:分布式版本控制系统. SVN.CVS:集中式版本控 ...
- <Android 应用 之路> MPAndroidChart~PieChart
简介 MPAndroidChart是PhilJay大神给Android开发者带来的福利.MPAndroidChart是一个功能强大并且使用灵活的图表开源库,支持Android和IOS两种,这里我们暂时 ...
- 【JavaScript】闭包应用之数据缓存
最近的开发中的许多事件会被频繁的触发,由于没有做缓存的处理,每次事件触发都会后台调用一样的数据.这几天我突然意识到自己的代码有很大的优化空间,继而想起了闭包可以有缓存的功能,于是乎便对其进行了深入的研 ...