ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

洛谷 P5559 失昼城的守星使

2021-08-22 07:32:52  阅读:139  来源: 互联网

标签:洛谷 守星 int ll ans P5559 num LCA 节点


Problem:

给定一个无向图,n个点,n-1条边,每个点有一个初始状态(标记/未标记),q个操作,每次操作修改一个点的状态(状态取反)/询问所有标记点到x->y的简单路径的距离之和。

Solution:

首先找到x->y的简单路径,然后求标记节点u到这条链的距离(u到LCA的距离减去u到LCA的路径与链的重合部分的长度),最后进行路径求和。

对于重合路径,对u->root的路径进行+1标记,然后每次查询链上路径和。

对于u->LCA的距离,有 dis(u,LCA)= dis(u,root)+ dis(LCA,root)- 2 * dis(lca(u,LCA))。

Code:

#include<bits/stdc++.h>
using namespace std; #define ll long long const int N=2e5+7; int n,m,a[N]; int dep[N];//节点深度 int f[N];//父节点 int son[N];//最大子节点 int sz[N];//子树大小 int top[N];//树链剖分后节点所在链的首节点 int num[N];//遍历次序 int LCA; int dfn=0;//记录遍历点个数 ll cnt=0;//标记点个数 ll siz[N];//子树中标记点个数 ll vis[N];//x->y简单路径不经过该节点时,节点子树中标记点接收信息在该路径上的能量消耗 ll pw[N];//连接父节点的边的边权 ll sw[N];//连接最大子节点的边的边权 ll tp; struct tree{ ll w; ll sum; ll lazy; }t[N<<2]; int head[N],tot=0; struct node{ int nxt,to,val; }e[N<<1]; //快读 inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } //建图 inline void add(int x,int y,int z){ e[++tot].nxt=head[x]; e[tot].to=y; e[tot].val=z; head[x]=tot; return ; } //预处理深度、父节点、子节点、标记、边权 inline void dfs1(int x,int fa){ f[x]=fa; dep[x]=dep[fa]+1; siz[x]=a[x]; sz[x]=1; for(int i=head[x];i;i=e[i].nxt){ int y=e[i].to; if(y!=fa){ dfs1(y,x); siz[x]+=siz[y]; sz[x]+=sz[y]; if(sz[son[x]]<sz[y]){ son[x]=y; sw[x]=e[i].val; } } } return ; } //预处理 inline void dfs2(int x,int tpx,ll ww){ ++dfn;//遍历个数 num[x]=dfn;//x节点是第num[x]个遍历到的 vis[dfn]=ww*siz[x];//第dfn个遍历到的节点的子树中标记点个数*该节点到父节点的路径长度 pw[dfn]=ww;//第dfn个遍历到的节点到父节点的路径长度 top[x]=tpx;//x节点所在链的链首节点 if(son[x]) dfs2(son[x],tpx,sw[x]);//递归重链 for(int i=head[x];i;i=e[i].nxt){ int y=e[i].to; int w=e[i].val; if(y!=son[x]&&y!=f[x]){ dfs2(y,y,w);//递归轻链 } } return ; } //递归建树 inline void build(int l,int r,int x){ if(l==r){ t[x].sum=pw[l]; t[x].w=vis[l]; return; } int mid=(l+r)>>1; build(l,mid,x<<1);//左子树 build(mid+1,r,x<<1|1);//右子树 t[x].w=t[x<<1].w+t[x<<1|1].w; t[x].sum=t[x<<1].sum+t[x<<1|1].sum; return ; } //更新 inline void pushdown(int x){ if(t[x].lazy){ t[x<<1].lazy+=t[x].lazy; t[x<<1|1].lazy+=t[x].lazy; t[x<<1].w+=t[x<<1].sum*t[x].lazy; t[x<<1|1].w+=t[x<<1|1].sum*t[x].lazy; t[x].lazy=0; } return ; } inline void update(int l,int r,int p,int q,int x,ll y){ if(p<=l&&r<=q){ t[x].lazy+=y; t[x].w+=t[x].sum*y;
return; } int mid=l+r>>1; pushdown(x); if(p<=mid) update(l,mid,p,q,x<<1,y); if(q>mid) update(mid+1,r,p,q,x<<1|1,y); t[x].w=t[x<<1].w+t[x<<1|1].w; return ; } //修改点的状态 inline void updt(int x,int y){ int pp=a[y]?-1:1;//取反 while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); update(1,n,num[top[x]],num[x],1,pp); x=f[top[x]]; } if(dep[x]>dep[y]) swap(x,y); update(1,n,num[x],num[y],1,pp); return ; } inline ll qu1(int l,int r,int p,int q,int x){ if(p>q) return 0; if(p<=l&&r<=q) return t[x].w; int mid=l+r>>1; ll ans=0; pushdown(x); if(p<=mid) ans=qu1(l,mid,p,q,x<<1); if(q>mid) ans+=qu1(mid+1,r,p,q,x<<1|1); return ans; } inline ll qu2(int l,int r,int p,int q,int x){ if(p>q) return 0; if(p<=l&&r<=q) return t[x].sum; int mid=l+r>>1; ll ans=0; pushdown(x); if(p<=mid) ans=qu2(l,mid,p,q,x<<1); if(q>mid) ans+=qu2(mid+1,r,p,q,x<<1|1); return ans; } inline ll qu4(int x,int y){ ll ans=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); ans+=qu2(1,n,num[top[x]],num[x],1); x=f[top[x]];
} if(dep[x]>dep[y]) swap(x,y); ans+=qu2(1,n,num[x]+1,num[y],1); return ans; } inline ll qu3(int x,int y){ ll ans=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); ans+=qu1(1,n,num[top[x]],num[x],1); x=f[top[x]]; } if(dep[x]>dep[y]) swap(x,y); ans+=qu1(1,n,num[x]+1,num[y],1); LCA=x; return ans; } inline ll find(int x,int y){ tp=qu3(x,y); int w=LCA; return t[1].w-tp-2ll*qu3(1,w)+cnt*qu4(1,w); } int main(){ n=read(); m=read(); tp=read(); for(int i=1;i<n;++i){ int u,v,w; u=read(); v=read(); w=read(); add(u,v,w); add(v,u,w); } for(int i=1;i<=n;++i) a[i]=read(); dfs1(1,0); dfs2(1,1,0); build(1,n,1); cnt=siz[1]; for(int i=1;i<=m;++i){ int opt=read(); int u=read(); if(opt==1){ cnt=cnt+(a[u]?-1:1);//更新cnt updt(1,u); a[u]=!a[u];//取反 } else{ int v=read(); printf("%lld\n",find(u,v)); } } return 0; }

标签:洛谷,守星,int,ll,ans,P5559,num,LCA,节点
来源: https://www.cnblogs.com/B-lank/p/15171207.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有