• 【BZOJ3626】[LNOI2014]LCA 离线+树链剖分+线段树


    【BZOJ3626】[LNOI2014]LCA

    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

    5 2
    0
    0
    1
    1
    1 4 3
    1 4 2

    Sample Output

    8
    5

    HINT

    共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。

    题解:考虑dep[lca(a,b)]可以表示成什么,我们将a到根路径上的每个节点的权值都+1,然后查询b到根的路径上的所有点的权值和即可。

    发现这个东西是可以用前缀和来搞的。我们将询问拆成前缀相减的形式,从1到n枚举i,将i到根路径上所有点的权值和+1,顺便处理当前的所有询问即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define mod 201314
    #define lson x<<1
    #define rson x<<1|1
    using namespace std;
    const int maxn=50010;
    int n,m,sum,tot,cnt;
    int to[maxn],next[maxn],head[maxn],deep[maxn],siz[maxn],fa[maxn],top[maxn],son[maxn],p[maxn];
    int s[maxn<<2],t[maxn<<2],ans[maxn];
    struct QUERY
    {
    	int qx,org,k,qz;
    }q[maxn<<1];
    inline int rd()
    {
    	int ret=0;	char gc=getchar();
    	while(gc<'0'||gc>'9')	gc=getchar();
    	while(gc>='0'&&gc<='9')	ret=(ret<<3)+(ret<<1)+gc-'0',gc=getchar();
    	return ret;
    }
    bool cmp(QUERY a,QUERY b)
    {
    	return a.qx<b.qx;
    }
    void dfs1(int x)
    {
    	siz[x]=1;
    	for(int i=head[x];i!=-1;i=next[i])
    	{
    		deep[to[i]]=deep[x]+1;
    		dfs1(to[i]);
    		siz[x]+=siz[to[i]];
    		if(siz[to[i]]>siz[son[x]])	son[x]=to[i];
    	}
    }
    void dfs2(int x,int tp)
    {
    	top[x]=tp,p[x]=++tot;
    	if(son[x])	dfs2(son[x],tp);
    	for(int i=head[x];i!=-1;i=next[i])	if(to[i]!=son[x])	dfs2(to[i],to[i]);
    }
    void pushdown(int l,int r,int x)
    {
    	if(t[x])
    	{
    		int mid=(l+r)>>1;
    		s[lson]=(s[lson]+(mid-l+1)*t[x])%mod;
    		s[rson]=(s[rson]+(r-mid)*t[x])%mod;
    		t[lson]+=t[x],t[rson]+=t[x],t[x]=0;
    	}
    }
    void updata(int l,int r,int x,int a,int b)
    {
    	if(a<=l&&r<=b)
    	{
    		s[x]+=r-l+1,t[x]++;
    		return ;
    	}
    	pushdown(l,r,x);
    	int mid=(l+r)>>1;
    	if(a<=mid)	updata(l,mid,lson,a,b);
    	if(b>mid)	updata(mid+1,r,rson,a,b);
    	s[x]=(s[lson]+s[rson])%mod;
    }
    int query(int l,int r,int x,int a,int b)
    {
    	if(a<=l&&r<=b)	return s[x];
    	pushdown(l,r,x);
    	int mid=(l+r)>>1;
    	if(b<=mid)	return query(l,mid,lson,a,b);
    	if(a>mid)	return query(mid+1,r,rson,a,b);
    	return query(l,mid,lson,a,b)+query(mid+1,r,rson,a,b);
    }
    void insert(int x)
    {
    	while(x)	updata(1,n,1,p[top[x]],p[x]),x=fa[top[x]];
    }
    int getsum(int x)
    {
    	int ret=0;
    	while(x)	ret=(ret+query(1,n,1,p[top[x]],p[x]))%mod,x=fa[top[x]];
    	return ret;
    }
    void add(int a,int b)
    {
    	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
    }
    int main()
    {
    	n=rd(),m=rd();
    	int i,j;
    	memset(head,-1,sizeof(head));
    	for(i=2;i<=n;i++)	fa[i]=rd()+1,add(fa[i],i);
    	deep[1]=1;
    	dfs1(1),dfs2(1,1);
    	for(i=1;i<=m;i++)
    	{
    		q[i*2-1].qx=rd(),q[i*2].qx=rd()+1;
    		q[i*2-1].qz=q[i*2].qz=rd()+1;
    		q[i*2-1].k=-1,q[i*2].k=1;
    		q[i*2-1].org=q[i*2].org=i;
    	}
    	sort(q+1,q+2*m+1,cmp);
    	for(i=1;i<=2*m;i++)
    	{
    		for(j=q[i-1].qx+1;j<=q[i].qx;j++)	insert(j);
    		ans[q[i].org]+=q[i].k*getsum(q[i].qz);
    	}
    	for(i=1;i<=m;i++)	printf("%d
    ",(ans[i]+mod)%mod);
    	return 0;
    }
  • 相关阅读:
    利用Multipeer Connectivity框架进行WiFi传输
    iOS 8创建交互式通知
    iOS开发网络篇—文件的上传
    iOS开发网络篇—发送GET和POST请求(使用NSURLSession)
    iOS之深入了解控制器View的加载
    工厂模式三部曲:工厂方法模式
    iOS web与js的简单交互
    精心整理的十个必须要知道CSS+DIV技巧
    [JQuery代码]超酷鼠标滑过背景高亮效果
    10个可以直接拿来用的JQuery代码片段
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7787734.html
Copyright © 2020-2023  润新知