[LNOI2014]LCA

[LNOI2014]LCA

https://ac.nowcoder.com/acm/contest/22131/A

题1 - [LNOI2014]LCA

题目支持q个询问[l,r]中的结点与z结点的lca的深度之和,即lirdeep[LCA(i,z)] \sum_{l≤i≤r} deep[LCA(i,z)]

思路:很明显,在1≤n≤50000,1≤m≤50000的条件下,在线查询lca的复杂度直接爆炸,因此我们考虑离线(嗯,想到这一步后就gg了)

既然直接查询lca不行,那么我们换一种想法。仔细想想,我们要查的其实并不是lca,而是lca的深度。
我们把 i 到根节点的这条链上权值+1,然后再询问 z 到根节点的链上权值之和,我们会发现,其实这就等于lca的深度。
因此,我们所要做的,就是让 i 从1开始跑,逐个将 i 到根节点的链上权值+1。(相当于做了个前缀和)
那么对于区间 l≤i≤r 来说,最后只需询问当 i=r 时,z 到根节点的链上权值之和,减去当 i=l-1 时,z 到根节点的链上权值之和。

代码:

#include<bits/stdc++.h>
#define ll long long
#define L(i,j,k) for(ll i=(j);i<=(k);i++)
#define R(i,j,k) for(ll i=(j);i>=(k);i--)
#define inf 0x3f3f3f3f3f3f3f3f
#define fi first
#define se second
#define MS(i,j) memset(i,j,sizeof (i))
const ll N=1e6+10,M=5,mod=998244353,mmod=mod-1;
const double pi=acos(-1);
using namespace std;
ll gcd(ll x,ll y){if(y==0) return x;return gcd(y,x%y);}
ll fksm(ll a,ll b){ll r=1;if(b<0)b+=mod-1;for(a%=mod;b;b>>=1){if(b&1)r=r*a%mod;a=a*a%mod;}return r;}//a 分母; b MOD-2
ll lowbit(ll x){return x&(-x);}

ll m,n,t,x,y,z,l,r,k,p,pp,nx,ny,ansx,ansy,lim,num,sum,pos,tot,root,block,key,cnt,minn,maxx,ans[N];
ll a[N],head[N],dx[5]={0,0,-1,1},dy[5]={-1,1,0,0};
double dans;
bool vis,flag;
char mapp,zz;
struct qq{ll x,id,k;}q;
struct tree{ll l,r,tag,sum;}trs[N*4];
struct Tree{ll fa,dep,dfn,siz,son,top,w;}tr[N];
struct Trp{ll l,r,fat,dep,n,w;}trp;
struct E{ll to,nxt,w;}eg[N*2];
struct matrix{ll n,m[M][M];};
struct complx{
	double r,i;
	complx(){}
	complx(double r,double i):r(r),i(i){}
	complx operator+(const complx& rhs)const{return complx (r+rhs.r,i+rhs.i);}
	complx operator-(const complx& rhs)const{return complx (r-rhs.r,i-rhs.i);}
	complx operator*(const complx& rhs)const{return complx (r*rhs.r-i*rhs.i,i*rhs.r+r*rhs.i);}
	void operator+=(const complx& rhs){r+=rhs.r,i+=rhs.i;}
	void operator*=(const complx& rhs){r=r*rhs.r-i*rhs.i,i=r*rhs.i+i*rhs.r;}
	void operator/=(const double& x){r/=x,i/=x;}
	complx conj(){return complx(r,-i);}
}; 

bool cmp(qq u,qq v){
    return u.x>v.x;
}
bool cmp1(qq u,qq v){
    return u.x<v.x;
}
bool cmpl(ll u,ll v){return u>v;}
struct cmps{bool operator()(ll u,ll v){
    return u>v;
}};//shun序

pair<ll,ll>pre;
vector<qq>v[N];//v.assign(m,vector<ll>(n));
//priority_queue<ll,vector<ll>,cmps>sp;
deque<qq>sq;
map<ll,ll>mp;
bitset<M>bi;

void add(ll u,ll v,ll w){
	eg[++cnt].to=v;
	eg[cnt].nxt=head[u];
	eg[cnt].w=w;
	head[u]=cnt;
}

void push_up(ll k){
	trs[k].sum=trs[k*2].sum+trs[k*2+1].sum;
}

void push_down(ll k){
	if(trs[k].tag){
		ll l=k*2,r=k*2+1;
		trs[l].tag+=trs[k].tag;
		trs[r].tag+=trs[k].tag;
		trs[l].sum+=(trs[l].r-trs[l].l+1)*trs[k].tag;
		trs[r].sum+=(trs[r].r-trs[r].l+1)*trs[k].tag;
		trs[k].tag=0; 
	}
}

void bd_tree(ll k,ll l,ll r){
	trs[k].tag=0;
	trs[k].l=l,trs[k].r=r;
	if(l==r){
		trs[k].sum=a[l];
		return;
	}
	ll mid=(l+r)/2;
	bd_tree(k*2,l,mid);
	bd_tree(k*2+1,mid+1,r);
	push_up(k);
}

ll query(ll k,ll pl,ll pr){
	ll ml=0,mr=0;
	if(trs[k].l>=pl&&trs[k].r<=pr){
		return trs[k].sum;
	}
	push_down(k);
	ll mid=(trs[k].l+trs[k].r)/2;
	if(mid>=pl)ml=query(k*2,pl,pr);
	if(mid+1<=pr)mr=query(k*2+1,pl,pr);
	return ml+mr;
}

void modify(ll k,ll pl,ll pr,ll val){
	if(trs[k].l>=pl&&trs[k].r<=pr){
		trs[k].sum+=(trs[k].r-trs[k].l+1)*val;
		trs[k].tag+=val;
		return;
	}
	push_down(k);
	ll mid=(trs[k].l+trs[k].r)/2;
	if(mid>=pl)modify(k*2,pl,pr,val);
	if(mid+1<=pr)modify(k*2+1,pl,pr,val);
	push_up(k);
}

void dfs1(ll x,ll ac){
	tr[x].fa=ac;
	tr[x].dep=tr[tr[x].fa].dep+1;
	tr[x].siz=1;
	ll k=head[x];
	while(k){
		ll y=eg[k].to;
		if(y!=ac){
			dfs1(y,x);
			tr[x].siz+=tr[y].siz;
			if(!tr[x].son||tr[y].siz>tr[tr[x].son].siz)tr[x].son=y;
		}
		k=eg[k].nxt;
	}
}

void dfs2(ll x,ll pos){
	tr[x].dfn=++tot;
	tr[x].top=pos;
	a[tot]=tr[x].w;
	if(!tr[x].son)return;
	dfs2(tr[x].son,pos);
	ll k=head[x];
	while(k){
		ll y=eg[k].to;
		if(y!=tr[x].fa&&y!=tr[x].son)dfs2(y,y);
		k=eg[k].nxt;
	} 
}

void mchain(ll x,ll y,ll val){
	while(tr[x].top!=tr[y].top){
		if(tr[tr[x].top].dep<tr[tr[y].top].dep)modify(1,tr[tr[y].top].dfn,tr[y].dfn,val),y=tr[tr[y].top].fa;
		else modify(1,tr[tr[x].top].dfn,tr[x].dfn,val),x=tr[tr[x].top].fa;
	}
	if(tr[x].dep>tr[y].dep)swap(x,y);
	modify(1,tr[x].dfn,tr[y].dfn,val);
}

ll qchain(ll x,ll y){
	ll res=0;
	while(tr[x].top!=tr[y].top){
		if(tr[tr[x].top].dep<tr[tr[y].top].dep)res+=query(1,tr[tr[y].top].dfn,tr[y].dfn),y=tr[tr[y].top].fa;
		else res+=query(1,tr[tr[x].top].dfn,tr[x].dfn),x=tr[tr[x].top].fa;
	}
	if(tr[x].dep>tr[y].dep)swap(x,y);
	res+=query(1,tr[x].dfn,tr[y].dfn);
	return res;
}

int main(){
	scanf("%lld%lld",&n,&m);
	cnt=0;
	L(i,2,n){
		scanf("%lld",&x);x++;//不喜欢用0做结点,所以全部结点++
		add(x,i,0);
		add(i,x,0);
	}
	tot=0;
	dfs1(1,0);
	dfs2(1,1);
	bd_tree(1,1,n);
	
	L(i,1,m){
		scanf("%lld%lld%lld",&x,&y,&z);
		x++,y++,z++;
		v[x-1].push_back({z,i,-1});
		v[y].push_back({z,i,1});
	}
	
	L(i,1,n){
		mchain(1,i,1);
		ll siz=v[i].size();
		L(j,0,siz-1){
			qq tmp=v[i][j];
			ans[tmp.id]+=tmp.k*qchain(1,tmp.x);
		}
	}
	L(i,1,m){
		printf("%lld\n",ans[i]%201314);
	}
}
全部评论

相关推荐

点赞 评论 收藏
分享
10-09 09:39
门头沟学院 C++
HHHHaos:这也太虚了,工资就一半是真的
点赞 评论 收藏
分享
最近又搬回宿舍了,在工位坐不住,写一写秋招起伏不断的心态变化,也算对自己心态的一些思考表演式学习从开始为实习准备的时候就特别焦虑,楼主一开始选择的是cpp后端,但是24届这个方向已经炸了,同时自己又因为本科非92且非科班,所以感到机会更加迷茫。在某天晚上用java写出hello&nbsp;world并失眠一整晚后选择老本行干嵌入式。理想是美好的,现实情况是每天忙但又没有实质性进展,总是在配环境,调工具,顺带还要推科研。而这时候才发现自己一直在表演式学习,徘徊在设想如何展开工作的循环里,导致没有实质性进展。现在看来当时如果把精力专注在动手写而不是两只手端着看教程,基本功或许不会那么差。实习的焦虑5月,楼主...
耶比:哲学上有一个问题,玛丽的房间:玛丽知道眼睛识别色彩的原理知道各种颜色,但是她生活在黑白的房间里,直到有一天玛丽的房门打开了她亲眼看到了颜色,才知道什么是色彩。我现在最大可能的减少对非工作事情的思考,如果有一件事困扰了我, 能解决的我就直接做(去哪里或者和谁吵架等等……),解决不了的我就不想了,每一天都是最年轻的一天,珍惜今天吧
投递比亚迪等公司10个岗位 > 秋招被确诊为…… 牛客创作赏金赛
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务