bzoj 3626: [LNOI2014]LCA 离线+树链剖分
3626: [LNOI2014]LCA
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 426 Solved: 124
[Submit][Status]
Description
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)
Input
第一行2个整数n q。
接下来n-1行,分别表示点1到点n-1的父节点编号。
接下来q行,每行3个整数l r z。
Output
输出q行,每行表示一个询问的答案。每个答案对201314取模输出
Sample Input
0
0
1
1
1 4 3
1 4 2
Sample Output
5
HINT
共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。
真是不知道那些人是如何想到这道题正解的,首先,区间查询都可以转化为前缀和的差值(就这个我都没想到),然后前缀和就想到了离线,按照点编号加点,查询[1,a]与z的答案,可以将z至根的路径赋值为1,询问[1,a]每个点到更路径点权和,而本题最神奇的地方是可以转化为将[1,a]所有点到根路径点权加1,询问z至根的点权和。
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 51100
#define MAXE MAXN*2
#define MAXQ MAXN
#define MAXV MAXN
#define MOD 201314
#define lch (now<<1)
#define rch (now<<1^1)
int n,m;
struct sgt_node
{
int l,r,sum,lzy;
}sgt[MAXN*];
void up(int now)
{
if (sgt[now].l==sgt[now].r)return;
sgt[now].sum=(sgt[lch].sum+sgt[rch].sum)%MOD;
}
void down(int now)
{
if (sgt[now].l==sgt[now].r)return;
if (sgt[now].lzy)
{
sgt[lch].lzy+=sgt[now].lzy;
sgt[rch].lzy+=sgt[now].lzy;
sgt[lch].sum=(sgt[lch].sum+sgt[now].lzy*(sgt[lch].r-sgt[lch].l+))%MOD;
sgt[rch].sum=(sgt[rch].sum+sgt[now].lzy*(sgt[rch].r-sgt[rch].l+))%MOD;
sgt[now].lzy=;
}
}
void Build_sgt(int now,int l,int r)
{
sgt[now].l=l;
sgt[now].r=r;
if (l==r)
{
return ;
}
Build_sgt(lch,l,(l+r)>>);
Build_sgt(rch,((l+r)>>)+,r);
}
void Add_sgt(int now,int l,int r)
{
if (sgt[now].l==l && sgt[now].r==r)
{
sgt[now].sum+=sgt[now].r-sgt[now].l+;
sgt[now].lzy++;
return ;
}
down(now);
int mid=(sgt[now].l+sgt[now].r)>>;
if (r<=mid)
{
Add_sgt(lch,l,r);
}else if (mid<l)
{
Add_sgt(rch,l,r);
}else
{
Add_sgt(lch,l,mid);
Add_sgt(rch,mid+,r);
}
up(now);
}
int Qry_sgt(int now,int l,int r)
{
if (sgt[now].l==l && sgt[now].r==r)
{
return sgt[now].sum%MOD;
}
int mid=(sgt[now].l+sgt[now].r)>>;
down(now);
if (r<=mid)
return Qry_sgt(lch,l,r);
if (mid<l)
return Qry_sgt(rch,l,r);
return (Qry_sgt(lch,l,mid)+Qry_sgt(rch,mid+,r))%MOD;
}
struct Edge
{
int np;
Edge *next;
}E[MAXE],*V[MAXV];
int tope=-;
void addedge(int x,int y)
{
E[++tope].np=y;
E[tope].next=V[x];
V[x]=&E[tope];
}
int siz[MAXN];
int depth[MAXN];
int son[MAXN];
int fa[MAXN];
int top[MAXN];
int pos[MAXN],dfstime=;
void dfs1(int now)
{
Edge *ne;
int mxsiz=;
siz[now]=;
for (ne=V[now];ne;ne=ne->next)
{
dfs1(ne->np);
siz[now]+=siz[ne->np];
if (siz[ne->np]>mxsiz)
{
mxsiz=siz[ne->np];
son[now]=ne->np;
}
}
}
void dfs2(int now)
{
Edge *ne;
pos[now]=++dfstime;
if (son[now])
{
top[son[now]]=top[now];
dfs2(son[now]);
}
for (ne=V[now];ne;ne=ne->next)
{
if (ne->np==son[now])continue;
top[ne->np]=ne->np;
dfs2(ne->np);
}
}
int q[MAXN];
struct qur_t
{
int x,y,z;
int ans;
}qur[MAXQ];
vector<pair<int,int> > vec[MAXN];
int main()
{
freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
int x,y,z,i,j,k;
scanf("%d%d",&n,&m);
for (i=;i<=n;i++)
{
scanf("%d",&x);x++;
fa[i]=x;
addedge(x,i);
}
dfs1();
top[]=;
dfs2();
Build_sgt(,,n);
for (i=;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
x++;y++;z++;
qur[i].x=x;
qur[i].y=y;
qur[i].z=z;
vec[x-].push_back(make_pair(z,));
vec[y].push_back(make_pair(z,));
}
vector<pair<int,int> >::iterator it1;
for (i=;i<=n;i++)
{
sort(vec[i].begin(),vec[i].end());
it1=unique(vec[i].begin(),vec[i].end());
while (vec[i].end()!=it1)vec[i].pop_back();
}
for (i=;i<vec[].size();i++)
{
vec[][i].second=;
}
int ans;
for (i=;i<=n;i++)
{
x=i;
while (x!=)
{
Add_sgt(,pos[top[x]],pos[x]);
x=fa[top[x]];
}
for (j=;j<vec[i].size();j++)
{
x=vec[i][j].first;
ans=;
while (x!=)
{
ans=(ans+Qry_sgt(,pos[top[x]],pos[x]))%MOD;
x=fa[top[x]];
}
vec[i][j].second=ans;
}
}
for (i=;i<m;i++)
{
ans=;
it1=lower_bound(vec[qur[i].x-].begin(),vec[qur[i].x-].end(),make_pair(qur[i].z,));
ans-=it1->second;
it1=lower_bound(vec[qur[i].y].begin(),vec[qur[i].y].end(),make_pair(qur[i].z,));
ans+=it1->second;
printf("%d\n",ans);
}
}
bzoj 3626: [LNOI2014]LCA 离线+树链剖分的更多相关文章
- [BZOJ 3626] [LNOI2014] LCA 【树链剖分 + 离线 + 差分询问】
题目链接: BZOJ - 3626 题目分析 考虑这样的等价问题,如果我们把一个点 x 到 Root 的路径上每个点的权值赋为 1 ,其余点的权值为 0,那么从 LCA(x, y) 的 Depth 就 ...
- 【BZOJ3626】[LNOI2014]LCA 离线+树链剖分+线段树
[BZOJ3626][LNOI2014]LCA Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度 ...
- [BZOJ3626] [LNOI2014] LCA 离线 树链剖分
题面 考虑到询问的\(l..r,z\)具有可减性,考虑把询问差分掉,拆成\(r,z\)和\(l-1,z\). 显然这些LCA一定在\(z\)到根的路径上.下面的问题就是怎么统计. 考虑不是那么暴力的暴 ...
- BZOJ 3626 LCA(离线+树链剖分)
首先注意到这样一个事实. 树上两个点(u,v)的LCA的深度,可以转化为先将u到根路径点权都加1,然后求v到根路径上的总点权值. 并且该题支持离线.那么我们可以把一个区间询问拆成两个前缀和形式的询问. ...
- 2018.09.16 bzoj3626: [LNOI2014]LCA(树链剖分)
传送门 树链剖分好题. 对于每个点维护一个值vi" role="presentation" style="position: relative;"&g ...
- BZOJ3626: [LNOI2014]LCA(树链剖分+线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...
- BZOJ 3626 [LNOI2014]LCA:树剖 + 差分 + 离线【将深度转化成点权之和】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3626 题意: 给出一个n个节点的有根树(编号为0到n-1,根节点为0,n <= 50 ...
- 【洛谷 P4211】[LNOI2014]LCA(树链剖分,差分)
题目链接 看到题目肯定首先想到要求LCA(其实是我菜),可乍一看,n与q的规模为5W, 求LCA的复杂度为\(O(logN)\),那么总时间复杂度为\(O(nq\ log\ n)\). 怎么搞呢? 会 ...
- [LNOI2014]LCA(树链剖分+线段树)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3626 题解:看到LCA,我们可以直接想到这题的正解不是LCA!(LCA只能得20分,还要 ...
随机推荐
- Java 加密 base64 encode
版权声明:本文为博主原创文章,未经博主允许不得转载. [前言] 计算机中的数据都是二进制的,不管是字符串还是文件,而加密后的也是二进制的, 而我们要看到的往往是字符串,本文就介绍了将byte[]转为各 ...
- linux下so动态库一些不为人知的秘密 系列
http://blog.chinaunix.net/uid-27105712-id-3313293.html http://www.cnblogs.com/gulvzhe/archive/2012/0 ...
- Quartz Enterprise Job Scheduler 1.x Tutorial---转载
Lesson 10: Configuration, Resource Usage and SchedulerFactory http://www.quartz-scheduler.org/docume ...
- ASP.NET Web API(一):使用初探,GET和POST数据
概述 REST(Representational State Transfer表述性状态转移)而产生的REST API的讨论越来越多,微软在ASP.NET中也添加了Web API的功能 项目建立 在安 ...
- android开发之merge结合include优化布局
merge结合include优化android布局,效果不知道,个人感觉使用上也有很大的局限,不过还是了解一下,记录下来. 布局文件都要有根节点,但android中的布局嵌套过多会造成性能问题,于是在 ...
- VC++判断是否连网
在开发中,需要判断是否有网络连接,于是写了个函数,实现代码如下: //判断是否有网络连接 static BOOL DoHaveInternetConnection() { BOOL bRet = FA ...
- Android(java)学习笔记169:Activity中的onCreate()方法分析
1.onCreate( )方法是android应用程序中最常见的方法之一: 翻译过来就是说,onCreate()函数是在activity初始化的时候调用的,通常情况下,我们需要在onCreate()中 ...
- 使用API在DigitalOcean上创建VPS
1.生成Personal Access Token(API-Token) 密钥类似如下格式: 81d58e36224b63fc2gedac14342d0cfb16vf5451c798b2a38f976 ...
- 关于基于.net的WEB程序开发所需要的一些技术归纳
前提: 最近公司里有一个同事,年龄比我大几岁,但是由于是转行来做开发的,许多的关于.net开发技术不是很入行,所以总是会问我一些东西,基于自己以前的一些 经验,总是会愿意给他讲一些总结性的东西,希望他 ...
- jQuery UI 日期控件--datepicker
在web开发中,日期的输入经常会遇到.我们会用的解决方法有: 1.自己写css和js,对日期进行控制:----有点浪费精力和时间: 2.用easyui插件中的日期插件来实现: 3.用juqery-ui ...