zoukankan      html  css  js  c++  java
  • 【LOJ#6073】距离(主席树)

    【LOJ#6073】距离(主席树)

    题面

    LOJ

    题解

    两点间的距离是(dep[x]+dep[y]-2dep[LCA])
    那么题目要求的东西拆开维护,唯一不好做的就是(2dep[LCA])
    而现在要求的是某个单点与一个点集的所有(LCA)的深度和。
    那么把点集中每一个点到根的路径全部标记一次路径长度,那么只需要求单点到根的权值和就好了。
    回到当前题目,既然要求的是一条路径上的东西,那么用主席树维护其到根的点集所影响的权值,最后减一减就好了。
    (是不是说得太简单了。。。。)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define ll long long
    #define MAX 200200
    inline ll read()
    {
    	ll x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int type,n,Q,p[MAX];
    struct Line{int v,next,w;}e[MAX<<1];
    int h[MAX],cnt=1;
    inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
    int dfn[MAX],low[MAX],tim,top[MAX],size[MAX],hson[MAX],dep[MAX],fa[MAX],V[MAX];
    ll sum[MAX],ans,dis[MAX],sdis[MAX];
    void dfs1(int u,int ff)
    {
    	size[u]=1;fa[u]=ff;dep[u]=dep[ff]+1;
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;if(v==ff)continue;
    		dis[v]=dis[u]+e[i].w;V[v]=e[i].w;
    		dfs1(v,u);size[u]+=size[v];
    		if(size[v]>size[hson[u]])hson[u]=v;
    	}
    }
    void dfs2(int u,int tp)
    {
    	top[u]=tp;dfn[u]=++tim;
    	if(hson[u])dfs2(hson[u],tp);
    	for(int i=h[u];i;i=e[i].next)
    		if(e[i].v!=fa[u]&&e[i].v!=hson[u])
    			dfs2(e[i].v,e[i].v);
    }
    int LCA(int u,int v)
    {
    	while(top[u]^top[v])dep[top[u]]<dep[top[v]]?v=fa[top[v]]:u=fa[top[u]];
    	return dep[u]<dep[v]?u:v;
    }
    struct Node{int ls,rs,s;ll v;}t[MAX<<6];
    int tot,rt[MAX];
    void Modify(int &x,int l,int r,int L,int R)
    {
    	t[++tot]=t[x];x=tot;
    	if(l==L&&r==R){++t[x].s;return;}
    	t[x].v+=sum[R]-sum[L-1];int mid=(l+r)>>1;
    	if(R<=mid)Modify(t[x].ls,l,mid,L,R);
    	else if(L>mid)Modify(t[x].rs,mid+1,r,L,R);
    	else Modify(t[x].ls,l,mid,L,mid),Modify(t[x].rs,mid+1,r,mid+1,R);
    }
    ll Query(int x,int l,int r,int L,int R)
    {
    	ll ret=(sum[R]-sum[L-1])*t[x].s;
    	if(L==l&&R==r)return ret+t[x].v;
    	int mid=(l+r)>>1;
    	if(R<=mid)return ret+Query(t[x].ls,l,mid,L,R);
    	if(L>mid)return ret+Query(t[x].rs,mid+1,r,L,R);
    	return ret+Query(t[x].ls,l,mid,L,mid)+Query(t[x].rs,mid+1,r,mid+1,R);
    }
    void dfs(int u,int ff)
    {
    	rt[u]=rt[ff];int x=p[u];sdis[u]=sdis[ff]+dis[x];
    	while(top[x])Modify(rt[u],1,n,dfn[top[x]],dfn[x]),x=fa[top[x]];
    	for(int i=h[u];i;i=e[i].next)
    		if(e[i].v!=ff)dfs(e[i].v,u);
    }
    ll Query(int u,int k)
    {
    	ll ret=dis[k]*dep[u]+sdis[u];
    	while(top[k])ret-=Query(rt[u],1,n,dfn[top[k]],dfn[k])*2,k=fa[top[k]];
    	return ret;
    }
    int main()
    {
    	type=read();n=read();Q=read();
    	for(int i=1;i<n;++i)
    	{
    		int u=read(),v=read(),w=read();
    		Add(u,v,w);Add(v,u,w);
    	}
    	dfs1(1,0);dfs2(1,1);
    	for(int i=1;i<=n;++i)p[i]=read();
    	for(int i=1;i<=n;++i)sum[dfn[i]]=V[i];
    	for(int i=1;i<=n;++i)sum[i]+=sum[i-1];
    	dfs(1,0);
    	while(Q--)
    	{
    		int u=read()^(type*ans),v=read()^(type*ans);
    		int lca=LCA(u,v),k=read()^(type*ans);
    		printf("%lld
    ",ans=Query(u,k)+Query(v,k)-Query(lca,k)-Query(fa[lca],k));
    	}
    	
    }
    
  • 相关阅读:
    leetcode 买卖股票的最佳时机3
    leetcode 买卖股票的最佳时机Ⅱ
    leetcode 最长有效括号
    C++中的%lld和%I64d区别
    Ural 1095 Nikifor 3 思维+同余性质的利用
    博弈基础
    ural 1091. Tmutarakan Exams
    容斥原理
    一些易错的地方
    codeforces911D Inversion Counting 求逆序数+小trick
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10202281.html
Copyright © 2011-2022 走看看