P6157 有趣的游戏
2022/4/30 23:15:43
本文主要是介绍P6157 有趣的游戏,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
P6157 有趣的游戏
分析
还是一样,看一看题目要求。
每一次系统会给出一条链,小 A 可以从这条链上找出两个点权不同的点 x,y,他的得分是 \(w_x mod w_y\)。然后小 B 会从整棵树中选取两个小 A 没有选过的点,计分方式同小 A。
非常容易推理出,对于A而言,其选出的最大答案是选出一条链的最大值与次大值,则对A而言最优解就是次大值
则对于B而言,B需要从被A扣出两个点的树中,选出最大值与次大值,对B来说最优的就是这个次大值
这个题最难的对我而言其实是,怎么从把A选的两个点抠出来了。
答案非常简单,用multiset就可以解决了。
直接从multiset中将A选中的删掉,再从multiset中找到最大值和次大值即可。
细节在代码中有注释。直接看。
Ac_code
#include<bits/stdc++.h> using namespace std; const int N = 1e5 + 10,M = N * 2; struct Node { int l,r,fi,se; }tr[N<<2]; int h[N],e[M],ne[M],w[N],idx; int sz[N],fa[N],son[N],dep[N]; int top[N],id[N],nw[N],ts; multiset<int> s; int n,q; void add(int a,int b) { e[idx] = b,ne[idx] = h[a],h[a] = idx++; } void dfs1(int u,int pa,int depth) { sz[u] = 1,dep[u] = depth; for(int i=h[u];~i;i=ne[i]) { int j = e[i]; if(j==pa) continue; fa[j] = u; dfs1(j,u,depth+1); sz[u] += sz[j]; if(sz[j]>sz[son[u]]) son[u] = j; } } void dfs2(int u,int tp) { top[u] = tp,id[u] = ++ts,nw[ts] = w[u]; if(!son[u]) return ; dfs2(son[u],tp); for(int i=h[u];~i;i=ne[i]) { int j = e[i]; if(j==fa[u]||j==son[u]) continue; dfs2(j,j); } } void push(Node &u,Node l,Node r) { u.fi = max(l.fi,r.fi); u.se = max(l.fi==u.fi?l.se:l.fi,r.fi==u.fi?r.se:r.fi); } void pushup(int u) { push(tr[u],tr[u<<1],tr[u<<1|1]); } void build(int u,int l,int r) { if(l==r) { tr[u] = {l,l,nw[l],-1};//因为维护的是严格次小值,因此,当区间长为1时,记得初始化次小值为-1,wa死我了 return ; } tr[u] = {l,r}; int mid = l + r >> 1; build(u<<1,l,mid),build(u<<1|1,mid+1,r); pushup(u); } void modify(int u,int x,int k) { if(tr[u].l==tr[u].r) { tr[u].fi += k;////因为维护的是严格次小值,因此,当区间长为1时,记得初始化次小值为-1,wa死我了 //因为这个原因,所有单点修的时候,就不要改次小值了,还是-1 return ; } int mid = tr[u].l + tr[u].r >> 1; if(x<=mid) modify(u<<1,x,k); else modify(u<<1|1,x,k); pushup(u); } Node query(int u,int l,int r) { if(l<=tr[u].l&&tr[u].r<=r) return tr[u]; int mid = tr[u].l + tr[u].r >> 1; Node res = {0,0,-1,-1}; if(l>mid) return query(u<<1|1,l,r); else if(r<=mid) return query(u<<1,l,r); else { auto left = query(u<<1,l,r),right = query(u<<1|1,l,r); push(res,left,right); return res; } } int main() { scanf("%d",&n); memset(h,-1,sizeof h); for(int i=0;i<n-1;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v),add(v,u); } for(int i=1;i<=n;i++) { int x;scanf("%d",&x); w[i] = x;s.insert(x); } scanf("%d",&q); dfs1(1,-1,1); dfs2(1,1); build(1,1,n); while(q--) { int op,x,y;scanf("%d%d%d",&op,&x,&y); if(!op) { s.erase(s.lower_bound(w[x]));//嗷,还有,单点修改后,记得将s中的对应删掉 //同时,给向我一样语法不好的同学,提一句,multiset里不要之间删数值,会把所有对应值删掉 //因此,可以先lower_bound找到,再删找到的对应迭代器的位置。 w[x] += y; s.insert(w[x]);//也不要忘记再加上 modify(1,id[x],y); } else { Node res = {0,0,-1,-1}; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); push(res,res,query(1,id[top[x]],id[x])); x = fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); push(res,res,query(1,id[y],id[x])); if(res.se==-1) puts("-1"); else { s.erase(s.lower_bound(res.fi)),s.erase(s.lower_bound(res.se)); printf("%d %d\n",res.se,*(--s.lower_bound(*--s.end())));//这里也是,找到最大值后,其前边的值不一定是次大值,直接二分查找 s.insert(res.fi),s.insert(res.se); } } } return 0; }
这篇关于P6157 有趣的游戏的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23JAVA语音识别项目入门教程
- 2024-11-23Java云原生学习:从入门到实践
- 2024-11-22Java创业学习:初学者的全面指南
- 2024-11-22JAVA创业学习:零基础入门到实战应用教程
- 2024-11-22Java创业学习:从零开始的Java编程入门教程
- 2024-11-22Java对接阿里云智能语音服务学习教程
- 2024-11-22JAVA对接阿里云智能语音服务学习教程
- 2024-11-22Java对接阿里云智能语音服务学习教程
- 2024-11-22Java副业学习:零基础入门到实战项目
- 2024-11-22Java副业学习:零基础入门指南