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;
}
标签:cnt,游戏,P6157,int,son,次大值,有趣,val
From: https://www.cnblogs.com/LG017/p/18590496