• 【题解】[LNOI2014]LCA


    题目戳我

    ( ext{Solution:})

    这题的转化思想很巧妙……

    考虑把(dep)给拆掉。

    首先可以明确的是,每一个(LCA)一定在(root o z)的路径上。

    考虑一个(LCA)被选中,意味(root o LCA)这个路径上所有的值都(+1).

    于是,我们可以把询问看成将点(pin [l,r],add(root o p,1))并从(z)向根的路径上求和即可。

    这个区间修改,区间查询显然的树剖线段树板子。而若对于每一个询问都做一次,复杂度显然不够。

    考虑将询问离线。

    将一个区间询问([l,r])拆成区间([l,l-1] and [1,r])并用差分的思想进行处理。于是,对每一个拆开的区间按照右端点排序(因为左端点都是(1))进行离线处理即可,这样就避免了每一次的清空操作。

    总结:对于一个(dep)的询问,我们可以看成:

    • (i)向根的路径上进行区间(+1).

    • (z)向根的路径上进行区间求和。

    这样,我们可以巧妙地通过区间加来规避对(dep)的询问。

    笔者一开始硬挖掘编号连续的性质往线段树维护深度和的歪路上走了很久……一度自闭

    值得记录的好题。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int MAXN=5e5+10;
    const int mod=201314;
    int dep[MAXN],siz[MAXN],top[MAXN],head[MAXN],rt;
    int tot,cnt,n,m,rk[MAXN],id[MAXN],dfstime,ls[MAXN];
    int rs[MAXN],pa[MAXN],son[MAXN],qcnt,Ans[MAXN];
    struct E{int nxt,to;}e[MAXN];
    inline void link(int x,int y){e[++tot]=(E){head[x],y};head[x]=tot;}
    inline int add(int x,int y){return (x+y)%mod;}
    inline int mul(int x,int y){return 1ll*x*y%mod;}
    struct SGT{int l,r,sum,tag;}tr[MAXN];
    inline void pushup(int x){tr[x].sum=tr[ls[x]].sum+tr[rs[x]].sum;}
    inline int LL(int x){return tr[x].r-tr[x].l+1;}
    inline void pushdown(int x){
    	if(tr[x].tag){
    		int p=tr[x].tag;tr[x].tag=0;
    		tr[ls[x]].tag+=p;tr[rs[x]].tag+=p;
    		tr[ls[x]].tag%=mod;tr[rs[x]].tag%=mod;
    		tr[ls[x]].sum=add(tr[ls[x]].sum,mul(LL(ls[x]),p));
    		tr[rs[x]].sum=add(tr[rs[x]].sum,mul(LL(rs[x]),p));
    	}
    }
    void build(int l,int r,int x){
    	tr[x].l=l,tr[x].r=r;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	ls[x]=cnt++;rs[x]=cnt++;
    	build(l,mid,ls[x]);
    	build(mid+1,r,rs[x]);
    	pushup(x);
    }
    void dfs1(int x,int fa){
    	pa[x]=fa,siz[x]=1,dep[x]=dep[fa]+1;
    	for(int i=head[x];i;i=e[i].nxt){
    		int j=e[i].to;
    		if(j==fa)continue;
    		dfs1(j,x);siz[x]+=siz[j];
    		if(siz[j]>siz[son[x]])son[x]=j;
    	}
    }
    void dfs2(int x,int t){
    	top[x]=t,rk[id[x]=++dfstime]=x;
    	if(!son[x])return;dfs2(son[x],t);
    	for(int i=head[x];i;i=e[i].nxt){
    		int j=e[i].to;
    		if(j!=pa[x]&&j!=son[x])dfs2(j,j);
    	}
    }
    void update(int l,int r,int v,int x){
    	if(tr[x].l>=l&&tr[x].r<=r){
    		tr[x].tag=add(tr[x].tag,v);
    		tr[x].sum=add(tr[x].sum,mul(LL(x),v));
    		return;
    	}
    	int mid=(tr[x].l+tr[x].r)>>1;pushdown(x);
    	if(l<=mid)update(l,r,v,ls[x]);
    	if(mid<r)update(l,r,v,rs[x]);
    	pushup(x);
    }
    int query(int l,int r,int x){
    	if(tr[x].l>=l&&tr[x].r<=r)return tr[x].sum;
    	int T=0,mid=(tr[x].l+tr[x].r)>>1;pushdown(x);
    	if(l<=mid)T=add(T,query(l,r,ls[x]));
    	if(mid<r)T=add(T,query(l,r,rs[x]));
    	pushup(x);return T;
    }
    void updatechain(int x,int y,int v){
    	while(top[x]!=top[y]){
    		if(dep[x]<dep[y])swap(x,y);
    		update(id[top[x]],id[x],v,rt);
    		x=pa[top[x]];
    	}
    	if(id[x]>=id[y])swap(x,y);
    	update(id[x],id[y],v,rt);
    }
    int querychain(int x,int y){
    	int ans=0;
    	while(top[x]!=top[y]){
    		if(dep[x]<dep[y])swap(x,y);
    		ans=add(ans,query(id[top[x]],id[x],rt));
    		x=pa[top[x]];
    	}
    	if(id[x]>id[y])swap(x,y);
    	ans=add(ans,query(id[x],id[y],rt));
    	return ans;
    }
    struct Query{int pos,num,fg,z;}q[MAXN];
    inline bool cmp(Query A,Query B){return A.pos<B.pos;}
    pair<int,int>ans[MAXN];
    signed main(){
    	scanf("%lld%lld",&n,&m);
    	for(int i=2;i<=n;++i){
    		int x;
    		scanf("%lld",&x);
    		x++;
    		link(x,i);link(i,x);
    	}
    	dfs1(1,0);dfs2(1,1);rt=cnt++;build(1,n,rt);
    	for(int i=1;i<=m;++i){
    		int a,b,c;
    		scanf("%lld%lld%lld",&a,&b,&c);
    		a++,b++,c++;
    		q[++qcnt]=(Query){a-1,i,0,c};
    		q[++qcnt]=(Query){b,i,1,c};
    	}
    	sort(q+1,q+qcnt+1,cmp);
    	int now=0;
    	for(int i=1;i<=qcnt;++i){
    		while(now<q[i].pos)updatechain(++now,1,1);
    		if(!q[i].fg)ans[q[i].num].first=querychain(q[i].z,1);
    		else ans[q[i].num].second=querychain(q[i].z,1);
    	}
    	for(int i=1;i<=m;++i)Ans[i]=(ans[i].second-ans[i].first+mod)%mod;
    	for(int i=1;i<=m;++i)printf("%lld
    ",Ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    Angular总结一:环境搭建
    适应移动端的地址四级(省市区街道)联动选择
    插入换行符
    自定义input[type="checkbox"]的样式
    使用zepto实现QQ消息左滑删除效果
    windows 下更新 npm 和 node
    [attribute |= value] 与 [attribute ^= value],[attribute ~= value] 与 [attribute *= value] 的联系与区别
    小程序父子组件onLoad和Created之间的问题
    小程序行内元素且有border的情况下,根据文字宽度自动调节元素宽度
    块级元素水平居中
  • 原文地址:https://www.cnblogs.com/h-lka/p/13773841.html
Copyright © 2020-2023  润新知