LNOI2014 LCA

题目链接:戳我

区间求和可以分成前缀和差分,所以我们可以把每次询问的l,r差分成\([1,r]-[1,l-1]\)

对于每一组询问,我们把\([l,r]\)内的每个点到根的链上都+1,然后x和根的链上的累加和就是LCA的深度总和了。

为什么呢?大家可以画画图,就显而易见了因为题目上说了LCA的深度为它到根结点的距离+1,那么从一个结点出发,给它到根结点的链上的节点累加1的时候,显然是从LCA开始才会对询问点产生贡献的。而这个贡献个就是从LCA开始,到根结点(包含),的点数,而这正等于题目中对LCA深度的定义。

然后这个问题就可以转换成树上区间加和,区间求和啦!这不就是树连剖分的模板了吗,显然一个一个求出来是不现实的,所以我们要考虑一次求出来很多个。所以我们先把所有询问都离线下来,然后我们按照pos从小到大排序,然后如果now==a[i].pos的时候,就可以累加给该询问答案了。

具体的请看代码吧 QAQ

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define MAXN 500010
#define mod 201314
using namespace std;

int n,Q,tt,cnt,tot;
int wt[MAXN],bit[MAXN],id[MAXN];
int head[MAXN<<1],fa[MAXN],topf[MAXN],dep[MAXN],top[MAXN],son[MAXN],siz[MAXN];

struct Edge{int nxt,to;}edge[MAXN<<1];
struct Node{int v,sum,l,r,tag;}t[MAXN<<4];
struct Node2{int pos,num,flag;}a[MAXN];
struct Que{int ans1,ans2,x;}q[MAXN];

inline bool cmp(struct Node2 x,struct Node2 y){return x.pos<y.pos;}

inline void add(int from,int to){edge[++tt].nxt=head[from],edge[tt].to=to,head[from]=tt;}

inline void dfs1(int x,int pre)
{
    dep[x]=dep[pre]+1;
	siz[x]=1;
	int maxx=-1;
    for(int i=head[x];i;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(v==pre) continue;
        dfs1(v,x);
		siz[x]+=siz[v];
		if(siz[v]>maxx) maxx=siz[x],son[x]=v;
    }
}

inline void dfs2(int x,int topf)
{
    top[x]=topf;
	id[x]=++cnt;
	if(son[x]) dfs2(son[x],topf);
    for(int i=head[x];i;i=edge[i].nxt)
    {
        int v=edge[i].to;
		if(v==fa[x]||v==son[x]) continue;
		dfs2(v,v);
    }
}

inline int ls(int x){return x<<1;}

inline int rs(int x){return x<<1|1;}

inline void push_up(int x){t[x].sum=(t[ls(x)].sum+t[rs(x)].sum)%mod;}

inline void f(int x,int k)
{
	int l=t[x].l,r=t[x].r;
	t[x].tag=(t[x].tag+k)%mod;
	t[x].sum=(t[x].sum+1ll*(r-l+1)*k%mod)%mod;
}

inline void push_down(int x)
{
	if(t[x].tag)
	{
		f(ls(x),t[x].tag);
		f(rs(x),t[x].tag);
		t[x].tag=0;
	}
}

inline void build(int x,int l,int r)
{
	t[x].l=l,t[x].r=r;
	if(l==r){t[x].sum=0;return;}
	int mid=(l+r)>>1;
	build(ls(x),l,mid);
	build(rs(x),mid+1,r);
	push_up(x);
}

inline void update(int x,int ll,int rr,int k)
{
	int l=t[x].l,r=t[x].r;
	if(ll<=l&&r<=rr) 
	{
		f(x,k);
		return;
	}
	int mid=(l+r)>>1;
	push_down(x);
	if(ll<=mid) update(ls(x),ll,rr,k);
	if(mid<rr) update(rs(x),ll,rr,k);
	push_up(x);
}

inline int query(int x,int ll,int rr)
{
	int l=t[x].l,r=t[x].r;
	if(ll<=l&&r<=rr) return t[x].sum;
	int mid=(l+r)>>1;
	push_down(x);
	int cur_ans=0;
	if(ll<=mid) cur_ans+=query(ls(x),ll,rr);
	if(mid<rr) cur_ans+=query(rs(x),ll,rr);
	return cur_ans;
}

inline void ADD(int x,int y)
{
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		update(1,id[top[x]],id[x],1);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	update(1,id[x],id[y],1);
}

inline int QUERY(int x,int y)
{
	int cur_ans=0;
	while(top[x]!=top[y])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		cur_ans=(cur_ans+query(1,id[top[x]],id[x]))%mod;
		x=fa[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	cur_ans=(cur_ans+query(1,id[x],id[y]))%mod;
	return cur_ans;
}


int main()
{
	#ifndef ONLINE_JUDGE
	freopen("ce.in","r",stdin);
	#endif
	scanf("%d%d",&n,&Q);
	n--;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&fa[i]);
		add(fa[i],i);
	}
	
	for(int i=1;i<=Q;i++)
	{
		int l,r;
		scanf("%d%d%d",&l,&r,&q[i].x);
		a[++tot].pos=l-1,a[tot].num=i,a[tot].flag=0;
		a[++tot].pos=r,a[tot].num=i,a[tot].flag=1;
	}
	build(1,1,n+1);
	dfs1(0,0);
	dfs2(0,0);
	// for(int i=0;i<=n;i++) printf("fa[%d]=%d\n",i,fa[i]); puts("");
	// for(int i=0;i<=n;i++) printf("dep[%d]=%d\n",i,dep[i]); puts("");
	// for(int i=0;i<=n;i++) printf("son[%d]=%d\n",i,son[i]); puts("");
	// for(int i=0;i<=n;i++) printf("siz[%d]=%d\n",i,siz[i]); puts("");
	// for(int i=0;i<=n;i++) printf("top[%d]=%d\n",i,top[i]); puts("");
	// for(int i=0;i<=n;i++) printf("id[%d]=%d\n",i,id[i]);
	int now=-1;
	sort(&a[1],&a[tot+1],cmp);
	for(int i=1;i<=tot;i++)
	{ 
		while(a[i].pos>now)
		{
			now++;
			ADD(now,0);
		}
		int maomao=a[i].num;
		if(a[i].flag==0) q[maomao].ans1=QUERY(q[maomao].x,0);
		if(a[i].flag==1) q[maomao].ans2=QUERY(q[maomao].x,0);
	}
	for(int i=1;i<=Q;i++)
		printf("%d\n",((q[i].ans2-q[i].ans1)%mod+mod)%mod);
    return 0;
}
posted @ 2019-04-26 16:58  风浔凌  阅读(199)  评论(0编辑  收藏  举报