ICode9

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

P6157 有趣的游戏

2022-04-30 22:01:33  阅读:159  来源: 互联网

标签:Node sz 游戏 P6157 int void son fi 有趣


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;
}

标签:Node,sz,游戏,P6157,int,void,son,fi,有趣
来源: https://www.cnblogs.com/aitejiu/p/16211516.html

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

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

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

ICode9版权所有