洛谷 P5559 失昼城的守星使
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:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 const int N=2e5+7; 6 7 int n,m,a[N]; 8 int dep[N];//节点深度 9 int f[N];//父节点 10 int son[N];//最大子节点 11 int sz[N];//子树大小 12 int top[N];//树链剖分后节点所在链的首节点 13 int num[N];//遍历次序 14 int LCA; 15 int dfn=0;//记录遍历点个数 16 ll cnt=0;//标记点个数 17 ll siz[N];//子树中标记点个数 18 ll vis[N];//x->y简单路径不经过该节点时,节点子树中标记点接收信息在该路径上的能量消耗 19 ll pw[N];//连接父节点的边的边权 20 ll sw[N];//连接最大子节点的边的边权 21 ll tp; 22 23 struct tree{ 24 ll w; 25 ll sum; 26 ll lazy; 27 }t[N<<2]; 28 29 int head[N],tot=0; 30 struct node{ 31 int nxt,to,val; 32 }e[N<<1]; 33 //快读 34 inline int read(){ 35 int x=0,f=1; 36 char ch=getchar(); 37 while(ch<'0'||ch>'9'){ 38 if(ch=='-') f=-1; 39 ch=getchar(); 40 } 41 while(ch>='0'&&ch<='9'){ 42 x=(x<<1)+(x<<3)+(ch^48); 43 ch=getchar(); 44 } 45 return x*f; 46 } 47 //建图 48 inline void add(int x,int y,int z){ 49 e[++tot].nxt=head[x]; 50 e[tot].to=y; 51 e[tot].val=z; 52 head[x]=tot; 53 return ; 54 } 55 //预处理深度、父节点、子节点、标记、边权 56 inline void dfs1(int x,int fa){ 57 f[x]=fa; 58 dep[x]=dep[fa]+1; 59 siz[x]=a[x]; 60 sz[x]=1; 61 for(int i=head[x];i;i=e[i].nxt){ 62 int y=e[i].to; 63 if(y!=fa){ 64 dfs1(y,x); 65 siz[x]+=siz[y]; 66 sz[x]+=sz[y]; 67 if(sz[son[x]]<sz[y]){ 68 son[x]=y; 69 sw[x]=e[i].val; 70 } 71 } 72 } 73 return ; 74 } 75 //预处理 76 inline void dfs2(int x,int tpx,ll ww){ 77 ++dfn;//遍历个数 78 num[x]=dfn;//x节点是第num[x]个遍历到的 79 vis[dfn]=ww*siz[x];//第dfn个遍历到的节点的子树中标记点个数*该节点到父节点的路径长度 80 pw[dfn]=ww;//第dfn个遍历到的节点到父节点的路径长度 81 top[x]=tpx;//x节点所在链的链首节点 82 if(son[x]) dfs2(son[x],tpx,sw[x]);//递归重链 83 for(int i=head[x];i;i=e[i].nxt){ 84 int y=e[i].to; 85 int w=e[i].val; 86 if(y!=son[x]&&y!=f[x]){ 87 dfs2(y,y,w);//递归轻链 88 } 89 } 90 return ; 91 } 92 //递归建树 93 inline void build(int l,int r,int x){ 94 if(l==r){ 95 t[x].sum=pw[l]; 96 t[x].w=vis[l]; 97 return; 98 } 99 int mid=(l+r)>>1; 100 build(l,mid,x<<1);//左子树 101 build(mid+1,r,x<<1|1);//右子树 102 t[x].w=t[x<<1].w+t[x<<1|1].w; 103 t[x].sum=t[x<<1].sum+t[x<<1|1].sum; 104 return ; 105 } 106 //更新 107 inline void pushdown(int x){ 108 if(t[x].lazy){ 109 t[x<<1].lazy+=t[x].lazy; 110 t[x<<1|1].lazy+=t[x].lazy; 111 t[x<<1].w+=t[x<<1].sum*t[x].lazy; 112 t[x<<1|1].w+=t[x<<1|1].sum*t[x].lazy; 113 t[x].lazy=0; 114 } 115 return ; 116 } 117 118 inline void update(int l,int r,int p,int q,int x,ll y){ 119 if(p<=l&&r<=q){ 120 t[x].lazy+=y; 121 t[x].w+=t[x].sum*y; 122 return; 123 } 124 int mid=l+r>>1; 125 pushdown(x); 126 if(p<=mid) update(l,mid,p,q,x<<1,y); 127 if(q>mid) update(mid+1,r,p,q,x<<1|1,y); 128 t[x].w=t[x<<1].w+t[x<<1|1].w; 129 return ; 130 } 131 //修改点的状态 132 inline void updt(int x,int y){ 133 int pp=a[y]?-1:1;//取反 134 while(top[x]!=top[y]){ 135 if(dep[top[x]]<dep[top[y]]) swap(x,y); 136 update(1,n,num[top[x]],num[x],1,pp); 137 x=f[top[x]]; 138 } 139 if(dep[x]>dep[y]) swap(x,y); 140 update(1,n,num[x],num[y],1,pp); 141 return ; 142 } 143 144 inline ll qu1(int l,int r,int p,int q,int x){ 145 if(p>q) return 0; 146 if(p<=l&&r<=q) return t[x].w; 147 int mid=l+r>>1; 148 ll ans=0; 149 pushdown(x); 150 if(p<=mid) ans=qu1(l,mid,p,q,x<<1); 151 if(q>mid) ans+=qu1(mid+1,r,p,q,x<<1|1); 152 return ans; 153 } 154 155 inline ll qu2(int l,int r,int p,int q,int x){ 156 if(p>q) return 0; 157 if(p<=l&&r<=q) return t[x].sum; 158 int mid=l+r>>1; 159 ll ans=0; 160 pushdown(x); 161 if(p<=mid) ans=qu2(l,mid,p,q,x<<1); 162 if(q>mid) ans+=qu2(mid+1,r,p,q,x<<1|1); 163 return ans; 164 } 165 166 inline ll qu4(int x,int y){ 167 ll ans=0; 168 while(top[x]!=top[y]){ 169 if(dep[top[x]]<dep[top[y]]) swap(x,y); 170 ans+=qu2(1,n,num[top[x]],num[x],1); 171 x=f[top[x]]; 172 } 173 if(dep[x]>dep[y]) swap(x,y); 174 ans+=qu2(1,n,num[x]+1,num[y],1); 175 return ans; 176 } 177 178 inline ll qu3(int x,int y){ 179 ll ans=0; 180 while(top[x]!=top[y]){ 181 if(dep[top[x]]<dep[top[y]]) swap(x,y); 182 ans+=qu1(1,n,num[top[x]],num[x],1); 183 x=f[top[x]]; 184 } 185 if(dep[x]>dep[y]) swap(x,y); 186 ans+=qu1(1,n,num[x]+1,num[y],1); 187 LCA=x; 188 return ans; 189 } 190 191 inline ll find(int x,int y){ 192 tp=qu3(x,y); 193 int w=LCA; 194 return t[1].w-tp-2ll*qu3(1,w)+cnt*qu4(1,w); 195 } 196 197 int main(){ 198 n=read(); 199 m=read(); 200 tp=read(); 201 for(int i=1;i<n;++i){ 202 int u,v,w; 203 u=read(); 204 v=read(); 205 w=read(); 206 add(u,v,w); 207 add(v,u,w); 208 } 209 for(int i=1;i<=n;++i) a[i]=read(); 210 dfs1(1,0); 211 dfs2(1,1,0); 212 build(1,n,1); 213 cnt=siz[1]; 214 for(int i=1;i<=m;++i){ 215 int opt=read(); 216 int u=read(); 217 if(opt==1){ 218 cnt=cnt+(a[u]?-1:1);//更新cnt 219 updt(1,u); 220 a[u]=!a[u];//取反 221 } 222 else{ 223 int v=read(); 224 printf("%lld\n",find(u,v)); 225 } 226 } 227 return 0; 228 }

浙公网安备 33010602011771号