P6157 有趣的游戏

P6157 有趣的游戏

题意简述:

给你一棵树,要求你维护一条链上任意两点 \(w_x\) \(mod\) \(w_y\) 的最大值,以及在去掉这两个点后的整棵树山任意两点\(w_{x'}\) \(mod\) \(w_{y'}\) 的最大值

Solution:

我们不难发现,在一些数中最大的 \(w_x\) \(mod\) \(w_y\) 其实就是严格次大值 mod 最大值,它的结果等于严格次大值

所以我们只需要建一颗线段树来维护区间前四大值$ w_{[0,3]}$,及其数量 $ cnt_{[0,3]}$ 。对前一种答案直接输出链上严格次大值,然后将链上最大值 \(w_0\) 与链上严格次大值 \(w_1\) 在线段树节点[1,n]上 cnt--,(如果存在的话),然后在临时更新后的[1,n]上查一个严格次大值 就好了

Code:

#include<bits/stdc++.h>
const int N=1e5+5;
using namespace std;
int n,m;
int w[N];
struct Tree{
    int l,r;
    int val[5],cnt[5];
};
struct Segment_Tree{
    #define ls x<<1
    #define rs x<<1|1
    Tree t[N<<2];
    void clear(Tree &T)
    {
        for(int i=0;i<4;i++){T.val[i]=T.cnt[i]=0;}
    }
    void pushup(Tree &T,Tree L,Tree R)
    {
        int i=0,j=0,k=0;
        while(k<4)
        {
            if(L.val[i]==R.val[j])
            {
                T.val[k]=L.val[i];
                T.cnt[k]=L.cnt[i]+R.cnt[j];
                i++,j++,k++;
            }
            if(L.val[i]>R.val[j]&&k<4)
            {
                T.val[k]=L.val[i];
                T.cnt[k]=L.cnt[i];
                i++,k++;
            }
            if(L.val[i]<R.val[j]&&k<4)
            {
                T.val[k]=R.val[j];
                T.cnt[k]=R.cnt[j];
                j++,k++;
            }
        }
    }
    void build(int x,int l,int r)
    {
        t[x].l=l,t[x].r=r;
        if(l==r){t[x].val[0]=w[l];t[x].cnt[0]=1;return ;}
        int mid=l+r>>1;
        build(ls,l,mid);build(rs,mid+1,r);
        pushup(t[x],t[ls],t[rs]);
    }
    void upd(int x,int pos,int k)
    {
        if(t[x].l==t[x].r){clear(t[x]);t[x].val[0]=k;t[x].cnt[0]=1;return ;}
        int mid=t[x].l+t[x].r>>1;
        if(pos<=mid)upd(ls,pos,k);
        if(mid<pos) upd(rs,pos,k);
        pushup(t[x],t[ls],t[rs]);
    }
    void query(int x,int L,int R,Tree &res)
    {
        if(L<=t[x].l&&t[x].r<=R)
        {
            pushup(res,res,t[x]);
            return ;
        }
        int mid=t[x].l+t[x].r>>1;
        if(L<=mid)query(ls,L,R,res);
        if(mid<R) query(rs,L,R,res);
    }
    #undef ls
    #undef rs
}T;
struct Graph{
    int head[N];
    struct Edge{
        int to,nxt;
    }e[N<<1];
    void add(int x,int y)
    {
        e[++head[0]]=Edge{y,head[x]};
        head[x]=head[0];
    }
    int fa[N],top[N],dep[N],dfn[N],rid[N],val[N];
    int son[N],siz[N];
    void dfs1(int x,int ff)
    {
        dep[x]=dep[ff]+1;fa[x]=ff;
        siz[x]=1;
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(y==fa[x])continue;
            dfs1(y,x);
            siz[x]+=siz[y];
            son[x] = siz[y] > siz[son[x]] ? y : son[x];
        }
    }
    void dfs2(int x,int tp)
    {
        dfn[x]=++dfn[0];rid[dfn[0]]=x;
        top[x]=tp;
        w[dfn[0]]=val[x];
        if(!son[x])return ;
        dfs2(son[x],tp);
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(y==fa[x]||y==son[x])continue;
            dfs2(y,y);
        }
    }
    Tree chain_query(int x,int y)
    {
        Tree res={0,0,{0},{0}};
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            T.query(1,dfn[top[x]],dfn[x],res);
            x=fa[top[x]];
        }
        if(dep[x]<dep[y])swap(x,y);
        T.query(1,dfn[y],dfn[x],res);
        return res;
    }

}G;
void work()
{
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        G.add(x,y);G.add(y,x);
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&G.val[i]);
    }
    G.dfs1(1,0);
    G.dfs2(1,1);
    T.build(1,1,n);
    cin>>m;
    for(int i=1;i<=m;i++)
    {
        int opt,x,y;
        scanf("%d%d%d",&opt,&x,&y);
        if(opt==0)
        {
            w[G.dfn[x]]+=y;
            T.upd(1,G.dfn[x],w[G.dfn[x]]);
        }
        if(opt==1)
        {
            Tree A=G.chain_query(x,y);
            Tree B={0,0,{0},{0}};
            T.query(1,1,n,B);
            if(!A.val[1]){printf("%d\n",-1);continue;}
            int ans_A=A.val[1],ans_B=0;
            for(int j=0;j<2;j++)for(int k=0;k<4;k++)if(A.val[j]==B.val[k])B.cnt[k]--;
            for(int k=0,tag=0;k<4;k++){if(tag&&B.cnt[k]>0){ans_B=B.val[k];break;}if(B.cnt[k]>0)tag=1;}
            printf("%d %d\n",ans_A,ans_B);
        }
    }
}
int main()
{
    //freopen("P6157.in","r",stdin);freopen("P6157.out","w",stdout);
    work();
    return 0;
}
posted @ 2024-12-06 12:11  liuboom  阅读(15)  评论(0)    收藏  举报