18寒假第三测
第一题:找LCA,两点之间的距离=他们各自到起点的距离 - 2*LCA到起点的距离
#include<bits/stdc++.h> using namespace std; const int maxn = 100015, P = 20; int head[2 * maxn],to[2 * maxn],last[2 *maxn],co[2 * maxn],dep[maxn], idx, anc[maxn][P+1],dis[maxn]; void dfs(int u,int from){ //in[u] = ++idx; anc[u][0] = from; for(int p = 1; p <= P; p++) anc[u][p] = anc[anc[u][p-1]][p-1]; for(int i = head[u]; i; i = last[i]){ if(to[i] != from){ dep[to[i]] = dep[u] + 1; dis[to[i]] = dis[u] + co[i]; dfs(to[i], u); } } } void adde(int u,int v,int w){ idx++; last[idx] = head[u]; to[idx] = v; co[idx] = w; head[u] = idx; } int lca(int u,int v){ if(dep[u] < dep[v])swap(u, v); int t = dep[u] - dep[v]; for(int p = 0; t; t >>= 1, p++) if(t & 1)u = anc[u][p]; if(u == v)return v; for(int p = P; p >=0; p--) if(anc[u][p] != anc[v][p]) u = anc[u][p], v = anc[v][p]; return anc[u][0]; } int main(){ freopen ( "distance.in", "r", stdin ) ; freopen ( "distance.out", "w", stdout ) ; int n,m; cin>>n; for(int i=1;i<n;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); adde( u, v, w ); adde( v, u, w ); } dfs(1,1); cin>>m; for(int i=1;i<=m;i++){ int u ,v; scanf("%d%d",&u,&v); int q = lca(u,v); printf("%d\n",dis[v]+dis[u]-dis[q]*2); } }
第二题:先dfs的dfn序,再投影得到一个序列,建线段树
#include<bits/stdc++.h> using namespace std; const int oo = 0x3f3f3f3f; #define MAX_N 100005 long long sum ; int head[MAX_N<<1],next[MAX_N<<1],to[MAX_N<<1]; int tot, a[MAX_N], in[MAX_N], out[MAX_N],dep[MAX_N],n, m, idx; void dfs(int u,int from){ in[u] = ++idx; for(int i = head[u]; i; i = next[i]){ int v = to[i]; if(v != from){ dep[v] = dep[u] + 1; dfs(v,u); } } out[u] = idx; } void adde(int u,int v){ ++tot; next[tot] = head[u]; to[tot] = v; head[u] = tot; } struct SegTree{ struct node{ long long sum; int vmin,vmax,lazy; }; node Tree[MAX_N << 2]; #define ls l, m, v << 1 #define rs m+1, r, v << 1 | 1 void push_up(int v){ Tree[v].sum = Tree[v << 1].sum + Tree[v << 1 | 1].sum; Tree[v].vmin = min(Tree[v << 1].vmin, Tree[v << 1 | 1].vmin); Tree[v].vmax = max(Tree[v << 1].vmax, Tree[v << 1 | 1].vmax); } void push_down(int l, int r, int v){ int m = (l + r) >> 1; Tree[v << 1].sum += 1LL * Tree[v].lazy * (m - l +1); Tree[v << 1].vmin += Tree[v].lazy; Tree[v << 1].vmax += Tree[v].lazy; Tree[v << 1].lazy += Tree[v].lazy; Tree[v << 1 | 1].sum += 1LL * Tree[v].lazy * (r - m); Tree[v << 1 | 1].vmin += Tree[v].lazy; Tree[v << 1 | 1].vmax += Tree[v].lazy; Tree[v << 1 | 1].lazy += Tree[v].lazy; Tree[v].lazy = 0; } void modify(int x,int L,int R,int l = 1, int r = n, int v = 1){ if(l >= L && r <= R){ Tree[v].lazy += x; Tree[v].sum += 1LL * x * (r - l + 1); Tree[v].vmin += x; Tree[v].vmax += x; } else { if(Tree[v].lazy)push_down(l,r,v); int m = (l + r) / 2; if(L <= m)modify(x,L,R,ls); if(R > m)modify(x,L,R,rs); push_up(v); } } node query(int L,int R,int l = 1, int r = n,int v = 1){ if(l >= L && r <= R) return Tree[v]; else { if(Tree[v].lazy) push_down(l,r,v); int m = (l + r) / 2; node ans; ans.vmin = oo, ans.vmax = -oo, ans.sum = 0; if(L <= m){ node nw = query(L,R,ls); ans.vmin = min(ans.vmin, nw.vmin); ans.vmax = max(ans.vmax, nw.vmax); ans.sum += nw.sum; } if(R > m){ node nw = query(L,R,rs); ans.vmin = min(ans.vmin, nw.vmin); ans.vmax = max(ans.vmax, nw.vmax); ans.sum += nw.sum; } return ans; } } }; SegTree Tr; int main(){ freopen("redpacket.in","r",stdin); freopen("redpacket.out","w",stdout); cin>>n; for(int i = 1; i < n; i++){ int u,v; scanf("%d%d",&u,&v); adde(u,v); adde(v,u); } dep[1] = 1; dfs(1,1); // Tr.build(); cin>>m; for(int i = 1; i <= m; i++){ string opt; cin>>opt; if(opt[0] == 'a'){ int u; scanf("%d",&u); SegTree::node nw; nw = Tr.query(in[u],out[u]); cout<<nw.sum<<endl; } else if(opt[0] == 'g'){ int u, x; scanf("%d%d",&u,&x); Tr. modify(x,in[u],out[u]); } else { int u; scanf("%d",&u); SegTree::node nw; nw = Tr.query(in[u],in[u]); cout<<nw.sum<<endl; } } }
第三题:比如这条红链上+5,在两个节点上+5,他们的LCA(root)-5,父节点也-5,单点query时就查子树和就好了
#include<bits/stdc++.h> using namespace std; const int maxn = 100005, P = 20; int in[maxn], f[maxn], head[2 * maxn],to[2 * maxn],last[2 *maxn],co[2 * maxn]; int idx, anc[maxn][P+1], dep[maxn], out[maxn], seq[maxn], idx1; vector <int> G[maxn]; int n,m; void dfs(int u,int from){ in[u] = ++idx; anc[u][0] = from; //fprintf(stderr, "from = %d u = %d\n",from, u); for(int p = 1; p <= P; p++) { // fprintf(stderr, "p = %d anc[%d][%d] = %d\n", p, u, p, anc[u][p]); anc[u][p] = anc[anc[u][p-1]][p-1]; } for(int i = head[u]; i; i = last[i]){ int v = to[i]; if(v != from){ dep[v] = dep[u] + 1; f[v] = u; dfs(v,u); } } out[u] = idx; } int lca(int u,int v){//倍增求LCA if(dep[u] < dep[v])swap(u, v); int t = dep[u] - dep[v]; for(int p = 0; t; t >>= 1, p++) if(t & 1)u = anc[u][p]; if(u == v)return v; for(int p = P; p >=0; p--) if(anc[u][p] != anc[v][p]) u = anc[u][p], v = anc[v][p]; return anc[u][0]; } int query(int x){ int ret = 0; while(x > 0){ ret += seq[x]; x -= (x & -x); } return ret; } void issum(int x,int val){ while(x <= n){ seq[x] += val; x += (x & -x); } } void adde(int u,int v){ idx1++; last[idx1] = head[u]; to[idx1] = v; head[u] = idx1; } int main(){ freopen("redpacket2.in","r",stdin); freopen("redpacket2.out","w",stdout); //ios::sync_with_stdio(false); cin>>n; for(int i = 1; i < n; i++){ int u,v; scanf("%d%d",&u,&v); adde(u,v); adde(v,u); } f[1] = 0; dep[1] = 1; dfs(1,1); cin>>m; for(int i = 1;i <= m; i++){ string opt; cin>>opt; if(opt[0] == 's'){ int u; scanf("%d",&u); printf("%d\n",query(out[u])-query(in[u]-1)); } else{ int u,v,val; scanf("%d%d%d",&u,&v,&val); issum(in[u],val); issum(in[v],val); int q = lca(u, v); issum(in[q],-val); int p = f[q]; if(p != 0) issum(in[p],-val); } } }