[LNOI2014]LCA
这道题难道不是数据结构水题吗 逃)
首先想到一个i点的\(dep\)相当于根节点走到i 进过的点之和,所以这个点对答案的贡献就是从这个点走到根节点。因此我们可以转换为当前节点\(i\)到根节点所经过的所有节点权值++。
显然可以用线段树+树链剖分的数据结构进行优化 对于每一个询问 建一颗权值线段树 存储当前区间\(sum\),\(sum\)存储的就是\(sum\)
然后我们需要想到用 类似于前缀和的思想来进行优化
例如 \(l=2 ,r=4 ,z=4\) 我们可以用前缀和的思想进行优化 计算\(1到4\)\(sum\)\(-1到1的sum\) 就可以得到答案了
想到了前缀和 想到了树剖+线段树 如果每一次查询 你都要新建两次树
那就会GG!
因此我们又想到了莫队的思想,将询问区间的\(l,r\)排序(因为询问区间为\(1到l\)\(1到r\),左区间都是一样的,所以我们可以将l,r一起排序),然后一个一个的加点 这样就可以不用每一次询问都新建一颗树了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long 
using namespace std;
const int mod=201314,maxn=100010;
int n,q,tot,fa[maxn],cnt_q;
int first[maxn],nxt[maxn<<1],to[maxn<<1],dep[maxn<<1],cnt_id;
int id[maxn<<1],rk[maxn<<1],size[maxn<<1],son[maxn<<1],top[maxn<<1],now;
int tag[maxn<<1],sum[maxn<<1];
struct node{
	int id,pos,z,flag;
	inline bool operator <(const node &x)const{
		return pos<x.pos || (x.pos==pos && id<x.id);
	}
}ques[maxn<<4];
struct node1{
	int ans1,ans2;
}ans[maxn<<2];
void dfs1(int x,int father){
	size[x]=1;fa[x]=father;
	for(int i=first[x];i;i=nxt[i]){
		int y=to[i];if(y==father) continue;
		dep[y]=dep[x]+1;
		dfs1(y,x);size[x]+=size[y];
		if(size[son[x]]<size[y])
			son[x]=y;
	}
}
void dfs2(int x,int topo){
	id[x]=++cnt_id;rk[cnt_id]=x;top[x]=topo;
	if(son[x])	dfs2(son[x],topo);
	for(int i=first[x];i;i=nxt[i]){
		int y=to[i];if(y==fa[y] || y==son[x]) continue;
		dfs2(y,y);
	}
}
void add(int x,int y){nxt[++tot]=first[x];first[x]=tot;to[tot]=y;}
void tagg(int node,int l,int r,int ta)
{
	sum[node]=(sum[node]+(r-l+1)*ta)%mod;
	if(l<r) tag[node]=(tag[node]+ta)%mod;	
}
void push_down(int node,int l,int r){
	if(l<r && tag[node]){
		int mid=(l+r)>>1;
		tagg(node<<1,l,mid,tag[node]);
		tagg(node<<1|1,mid+1,r,tag[node]);
	}
	tag[node]=0;
}
void push_up(int node){sum[node]=(sum[node<<1]+sum[node<<1|1])%mod;}
void modify(int node,int l,int r,int ql,int qr){
	if(qr<l || ql>r) return ;
	if(ql<=l && r<=qr){
		tagg(node,l,r,1);
		return ;
	}
	push_down(node,l,r);
	int mid=(l+r)>>1;
	modify(node<<1,l,mid,ql,qr);modify(node<<1|1,mid+1,r,ql,qr);
	push_up(node);
}
void line_modify(int x,int y){
	int tx=top[x],ty=top[y];
	while(tx!=ty){
		if(dep[tx]<dep[ty]){
			x^=y^=x^=y;tx^=ty^=tx^=ty;
		}
		modify(1,1,n,id[tx],id[x]);
		x=fa[tx];tx=top[x];
	}
	if(dep[x]<dep[y])
		x^=y^=x^=y;
	modify(1,1,n,id[y],id[x]);
}
int query(int node,int l,int r,int ql,int qr){
	if(ql<=l && r<=qr)	return (sum[node]%mod);
	push_down(node,l,r);
	int mid=(l+r)>>1,anss=0;
	if(ql<=mid)	anss+=query(node<<1,l,mid,ql,qr);
	if(mid<qr) anss+=query(node<<1|1,mid+1,r,ql,qr);
	return anss%mod;
}
int line_query(int x,int y){
	int tx=top[x],ty=top[y],anss=0;
	while(tx!=ty){
		if(dep[tx]<dep[ty]){
			x^=y^=x^=y;tx^=ty^=tx^=ty;
		}
		anss+=query(1,1,n,id[tx],id[x]);
		anss%=mod;
		x=fa[tx];tx=top[x];
	}
	if(dep[x]<dep[y])
		x^=y^=x^=y;
	anss+=query(1,1,n,id[y],id[x]);
	return anss%mod;
}
signed main(){
	scanf("%lld %lld",&n,&q);
	for(int i=2,x;i<=n;i++){
		scanf("%lld",&x);add(++x,i);
	}
		
	dep[1]=1;
	dfs1(1,0);dfs2(1,1);
	for(int i=1,l,r,z;i<=q;i++){
		 scanf("%lld %lld %lld",&l,&r,&z);r++;z++;
		 ques[++cnt_q]=((node){i,l,z,0});ques[++cnt_q]=((node){i,r,z,1});
	}
	sort(ques+1,ques+1+cnt_q);now=0;
	for(int i=1;i<=cnt_q;i++){
		while(now<ques[i].pos)
			line_modify(1,++now);
		int num=ques[i].id;
		if(ques[i].flag==1)	ans[num].ans1=line_query(1,ques[i].z);
		else ans[num].ans2 =line_query(1,ques[i].z);
	}
	for(int i=1;i<=q;i++)
		printf("%lld\n",(ans[i].ans1-ans[i].ans2+mod)%mod);
	return 0;
}
posted on 2019-10-25 16:49  萌德真帅  阅读(125)  评论(0编辑  收藏  举报