【树链剖分】【线段树】bzoj3626 [LNOI2014]LCA

引用题解:

http://blog.csdn.net/popoqqq/article/details/38823457

题目大意:

给出一个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的最近公共祖先的深度之和)

这题看见了直接卡壳。。。然后看了题解才搞懂要怎么写。。。

直接复制gconeice的题解吧 

显然,暴力求解的复杂度是无法承受的。
考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案。观察到,深度其实就是上面有几个已标记了的点(包括自身)。所以,我们不妨把 z 到根的路径上的点全部 +1,对于 l 到 r 之间的点询问他们到根路径上的点权和。仔细观察上面的暴力不难发现,实际上这个操作具有叠加性,且可逆。也就是说我们可以对于 l 到 r 之间的点 i,将 i 到根的路径上的点全部 +1, 转而询问 z 到根的路径上的点(包括自身)的权值和就是这个询问的答案。把询问差分下,也就是用 [1, r] − [1, l − 1] 来计算答案,那么现在我们就有一个明显的解法。从 0 到 n − 1 依次插入点 i,即将 i 到根的路径上的点全部+1。离线询问答案即可。我们现在需要一个数据结构来维护路径加和路径求和,显然树链剖分或LCT 均可以完成这个任务。树链剖分的复杂度为 O((n + q)· log n · log n),LCT的复杂度为 O((n + q)· log n),均可以完成任务。至此,题目已经被我们完美解决。

写的很详细,我就不累述了

同样是14年的省选,同样是树链剖分,为啥辽宁省的就如此牛B,吉林省的就是水题。。。差距好大0.0

取模的话数字不是很大 可以开long long 最后取一下模就好了 中途不要取模 弄成负的WA了我一下午0.0 又一下午0.0 又一下午0.0 啊啊啊啊啊啊啊啊啊

——PoPoQQQ

 

#include<cstdio>
#include<algorithm>
using namespace std;
#define N 50001
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
struct ASK{int p,z,id;}Q[N<<1];
int n,m;
bool operator < (const ASK &a,const ASK &b){return a.p<b.p;}
int sumv[N<<2],delta[N<<2];
void pushdown(int rt,int sz)
{
	if(delta[rt])
	  {
	  	sumv[rt<<1]+=(sz-(sz>>1))*delta[rt];
	  	sumv[rt<<1|1]+=(sz>>1)*delta[rt];
	  	delta[rt<<1]+=delta[rt];
	  	delta[rt<<1|1]+=delta[rt];
	  	delta[rt]=0;
	  }
}
void update(int ql,int qr,int rt,int l,int r)
{
	if(ql<=l&&r<=qr)
	  {
	  	sumv[rt]+=(r-l+1);
	  	++delta[rt];
	  	return;
	  }
	pushdown(rt,r-l+1);
	int m=(l+r>>1);
	if(ql<=m) update(ql,qr,lson);
	if(m<qr) update(ql,qr,rson);
	sumv[rt]=sumv[rt<<1]+sumv[rt<<1|1];
}
int query(int ql,int qr,int rt,int l,int r)
{
	if(ql<=l&&r<=qr) return sumv[rt];
	pushdown(rt,r-l+1);
	int m=(l+r>>1),res=0;
	if(ql<=m) res+=query(ql,qr,lson);
	if(m<qr) res+=query(ql,qr,rson);
	return res;
}
int v[N],en,first[N],next[N];
void AddEdge(int U,int V)
{
	v[++en]=V;
	next[en]=first[U];
	first[U]=en;
}
int top[N],tot,Num[N],fa[N],siz[N],son[N];
void dfs(int U)
{
	siz[U]=1;
	for(int i=first[U];i;i=next[i])
	  {
	    dfs(v[i]);
	    siz[U]+=siz[v[i]];
	    if(siz[v[i]]>siz[son[U]])
	      son[U]=v[i];
	  }
}
void df2(int U)
{
	Num[U]=++tot;
	if(son[U])
	  {
	  	top[son[U]]=top[U];
	  	df2(son[U]);
	  }
	for(int i=first[U];i;i=next[i])
	  if(v[i]!=son[U])
	    {
	      top[v[i]]=v[i];
	      df2(v[i]);
	    }
}
void Update(int U)
{
	while(top[U]!=1)
	  {
	  	update(Num[top[U]],Num[U],1,1,n);
	  	U=fa[top[U]];
	  }
	update(1,Num[U],1,1,n);
}
int Query(int U)
{
	int res=0;
	while(top[U]!=1)
	  {
	  	res+=query(Num[top[U]],Num[U],1,1,n);
	  	U=fa[top[U]];
	  }
	return res+query(1,Num[U],1,1,n);
}
int pre[N],ans[N];
int main()
{
	int x;
	scanf("%d%d",&n,&m);
	for(int i=2;i<=n;++i)
	  {
	  	scanf("%d",&x);
	  	AddEdge(x+1,i);
	  	fa[i]=x+1;
	  }
	top[1]=1;
	dfs(1);
	df2(1);
	for(int i=1;i<=m;++i)
	  {
	  	scanf("%d%d%d",&Q[(i<<1)-1].p,&Q[i<<1].p,&Q[(i<<1)-1].z);
	  	++Q[(i<<1)-1].z;
	  	++Q[i<<1].p;
	  	Q[(i<<1)-1].id=(i<<1)-1;
	  	Q[i<<1].z=Q[(i<<1)-1].z;
	  	Q[i<<1].id=(i<<1);
	  }
	sort(Q+1,Q+(m<<1|1));
	for(int i=1;i<=(m<<1);++i)
	  {
	  	for(int j=Q[i-1].p+1;j<=Q[i].p;++j)
	  	  Update(j);
	  	if(!(Q[i].id&1)) ans[Q[i].id>>1]=Query(Q[i].z)-pre[Q[i].id>>1];
	  	else pre[(Q[i].id+1)>>1]=Query(Q[i].z);
	  }
	for(int i=1;i<=m;++i)
	  printf("%d\n",ans[i]%201314);
	return 0;

 

posted @ 2015-03-18 07:22  AutSky_JadeK  阅读(183)  评论(0编辑  收藏  举报
TVアニメ「Charlotte(シャーロット)」公式サイト TVアニメ「Charlotte(シャーロット)」公式サイト