bzoj 3626 [LNOI2014]LCA

题目大意

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

分析

我们考虑将z到根每个点权+1
询问l-r中每个点到根点权和,加起来,就是答案
一个点dep就是到根点权和
这是可逆的
我们可以l-r中每个点到根点权+1
再询问z
离线差分一下

注意

考前了还有这种低级错误
1.先看清题,别着急写又改来改去的,改又改得不全
2.做完题检查至少3次
细节,数组,longlong,取模等,仔仔细细的看
3.如果还是虚就对拍一下

solution

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
const int M=100007;
const int Q=201314;
typedef long long LL;

inline int rd(){
	int x=0;bool f=1;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
	for(;isdigit(c);c=getchar()) x=x*10+c-48;
	return f?x:-x;
}

int n,m;
int g[M],te;
struct edge{int y,next;}e[M<<1];

void addedge(int x,int y){
	e[++te].y=y;e[te].next=g[x];g[x]=te;
}

int hd[M],tq;
struct query{int z,id,next;}ask[M<<1];

void addask(int x,int z,int id){
	ask[++tq].z=z;ask[tq].id=id;ask[tq].next=hd[x];hd[x]=tq;
}

int dep[M],sz[M];
int son[M],pre[M];
int tid[M],pid[M];
int top[M],tdfn;
int ans[M];
struct Seg{
	int sum;
	int tag;
}a[M<<2];

void dfs1(int x){
	sz[x]=1;
	son[x]=0;
	int p,y;
	for(p=g[x];p;p=e[p].next)
	if((y=e[p].y)!=pre[x]){
		dep[y]=dep[x]+1;
		pre[y]=x;
		dfs1(y);
		sz[x]+=sz[y];
		if(sz[y]>sz[son[x]]) son[x]=y;
	}
}

void dfs2(int x){
	int p,y;
	tid[x]=++tdfn;
	pid[tdfn]=x;
	if(son[x]){
		top[son[x]]=top[x];
		dfs2(son[x]);
	}
	for(p=g[x];p;p=e[p].next)
	if((y=e[p].y)!=pre[x]&&y!=son[x]){
		top[y]=y;
		dfs2(y);
	}
}

void ins(int x,int l,int r,int tl,int tr,int d){
	if(tl<=l&&r<=tr){
		a[x].tag=(a[x].tag+d)%Q;
		a[x].sum=(a[x].sum+((LL)d*(tr-tl+1)%Q))%Q;
		return;
	}
	int mid=l+r>>1;
	if(tr<=mid) ins(x<<1,l,mid,tl,tr,d);
	else if(mid<tl) ins(x<<1|1,mid+1,r,tl,tr,d);
	else ins(x<<1,l,mid,tl,mid,d),ins(x<<1|1,mid+1,r,mid+1,tr,d);
	a[x].sum=(a[x].sum+((LL)d*(tr-tl+1)%Q))%Q;
}

int get(int x,int l,int r,int tl,int tr){
	if(tl<=l&&r<=tr) return a[x].sum;
	int mid=l+r>>1;
	int res=((LL)a[x].tag*(tr-tl+1))%Q;
	if(tr<=mid) res=(res+get(x<<1,l,mid,tl,tr))%Q;
	else if(mid<tl) res=(res+get(x<<1|1,mid+1,r,tl,tr))%Q;
	else res=(res+get(x<<1,l,mid,tl,mid)+get(x<<1|1,mid+1,r,mid+1,tr))%Q;
	return res;
}

void chg(int x,int to){
	for(;dep[top[x]]>=dep[to];x=pre[top[x]])
		ins(1,1,n,tid[top[x]],tid[x],1);
	if(dep[x]>=dep[to])
		ins(1,1,n,tid[to],tid[x],1);		
}

int getsum(int x,int to){
	int res=0;
	for(;dep[top[x]]>=dep[to];x=pre[top[x]])
		res=(res+get(1,1,n,tid[top[x]],tid[x]))%Q;
	if(dep[x]>=dep[to])
		res=(res+get(1,1,n,tid[to],tid[x]))%Q;
	return res;
}

int main(){
	int p,i,x,y,z;
	n=rd(),m=rd();
	for(i=2;i<=n;i++){
		y=rd()+1;
		addedge(i,y);
		addedge(y,i);
	}
	
	dep[1]=1;
	pre[1]=0;
	dfs1(1);
	
	top[1]=1;
	dfs2(1);
	
	for(i=1;i<=m;i++){
		x=rd()+1,y=rd()+1,z=rd()+1;
		x--;
		if(x) addask(x,z,-i);
		addask(y,z,i);
	}
	
	for(i=1;i<=n;i++){
		chg(i,1);
		for(p=hd[i];p;p=ask[p].next){
			x=abs(ask[p].id);
			if(ask[p].id<0) ans[x]=(ans[x]-getsum(ask[p].z,1))%Q;
			else ans[x]=(ans[x]+getsum(ask[p].z,1))%Q;
		}
	}
	
	for(i=1;i<=m;i++) printf("%d\n",(ans[i]%Q+Q)%Q);	
	return 0;
}
posted @ 2017-02-17 14:28  _zwl  阅读(170)  评论(0编辑  收藏  举报