题目描述
在 C 国中有 n 位士兵,除士兵 1 外,每位士兵 i 均有且仅有一位士兵
j(j<i)
j
(
j
<
i
)
作为他的直属教官。士兵 i 被他的直属教官 j 以及所有能管辖 j 的士兵所管辖。每位士兵也看做能管辖自己。
每位士兵均有两个属性值:战斗力
bi
b
i
与领导力
li
l
i
。
现在 C 国要举行 q 次阅兵,每次阅兵会指定一位士兵 s 做总指挥,士兵 s需要训练自己所管辖的所有士兵,并以最好的精神面貌迎接阅兵式。
士兵 s 每次阅兵训练时有一次机会(只能使用一次或不使用),可以邀请一位不受他管辖的士兵 i 来指导一位他所管辖的士兵 j,并会使得士兵 j 的战斗力由
bj
b
j
提升为
bj+li
b
j
+
l
i
,这次提升仅对当次阅兵有效。
士兵 s 训练出的士兵队伍所能展现出的精神力 P 为:
Max
M
a
x
{
bi
b
i
%
bj
b
j
},i、j 被s管辖
现在 C 国主席想知道,每次阅兵的队伍所能展现出的精神力 P 最大能是多少?请你帮助他。
输入格式
第一行两个数 n,q 表示士兵数以及阅兵次数。
接下来一行 n-1 个整数,第 i 个整数表示士兵 i+1 的直属教官。
接下来 n 行每行两个整数
bi,li
b
i
,
l
i
描述一位士兵的属性。
接下来 q 行每行一个整数
si
s
i
,表示这次阅兵的总指挥。
输出格式
对于每次阅兵输出一行一个整数,表示阅兵队伍能展现出的最大精神力 P。
样例输入
5 2
1 1 2 2
2 1
1 5
4 2
2 3
3 1
1
2
样例输出1
3
3
样例输入2
7 3
1 1 2 2 3 3
3 0
1 3
5 2
2 0
4 1
3 1
2 2
1
2
3
样例输出2
5
3
4
题解
0817 Orz
简化题意,即:允许将s的子树中的一个点加上某一权值(也可以不加),求不同方法更新后的子树严格次大值的最大值。
我们记录子树中原来的战斗力最大值、次大值、第三大值分别为
b0,b1,b2
b
0
,
b
1
,
b
2
,子树外的领导力最大值、次大值为
l0,l1
l
0
,
l
1
。要求
b0≥b1,b1>b2,l0>l1
b
0
≥
b
1
,
b
1
>
b
2
,
l
0
>
l
1
当
b1+l0≠b0
b
1
+
l
0
≠
b
0
时,显然将
b1
b
1
加上
l0
l
0
是最优的
当
b1+l0=b0
b
1
+
l
0
=
b
0
时,显然不能这样加(否则mod出来是0)。于是就有两种可能的答案:
b1+l1
b
1
+
l
1
和
l0+b2
l
0
+
b
2
。对两种答案取Max即可
子树问题,可用DFS序化为序列区间问题。可以用线段树维护子树战斗力极值,用前缀后缀维护不在子树的领导力极值。
代码
#include <cstdio>
#include <iostream>
using namespace std;
struct dt{
int v0,v1,v2;
}maxn[1110000];
struct node{
int v0,v1;
}frl[222222],bel[222222];
int b[222222],l[222222];
int newid[222222];
node MEX(node a,node b)
{
node ans;
ans.v0=max(a.v0,b.v0);
ans.v1=a.v1;
if(a.v0<ans.v0)ans.v1=max(ans.v1,a.v1);
if(b.v0<ans.v0)ans.v1=max(ans.v1,b.v0);
if(b.v1<ans.v0)ans.v1=max(ans.v1,b.v1);
return ans;
}
dt MAX(dt a,dt b)
{
dt ans;
if(a.v0>b.v0)
{
ans.v0=a.v0;
ans.v1=max(a.v1,b.v0);
ans.v2=a.v2;
if(a.v1<ans.v1)ans.v2=max(ans.v2,a.v1);
if(b.v0<ans.v1)ans.v2=max(ans.v2,b.v0);
if(b.v1<ans.v1)ans.v2=max(ans.v2,b.v1);
if(b.v2<ans.v2)ans.v2=max(ans.v2,b.v2);
}
else{
ans.v0=b.v0;
ans.v1=max(b.v1,a.v0);
ans.v2=b.v2;
if(b.v1<ans.v1)ans.v2=max(ans.v2,b.v1);
if(a.v0<ans.v1)ans.v2=max(ans.v2,a.v0);
if(a.v1<ans.v1)ans.v2=max(ans.v2,a.v1);
if(a.v2<ans.v2)ans.v2=max(ans.v2,a.v2);
}
return ans;
}
void init(int now,int l,int r)
{
if(l==r){
maxn[now].v0=b[newid[l]];
maxn[now].v1=-1000000000;
maxn[now].v2=-1000000001;
return;
}
int mid=l+r >>1,ls=now<<1,rs=(now<<1)|1;
init(ls,l,mid);
init(rs,mid+1,r);
maxn[now]=MAX(maxn[ls],maxn[rs]);
}
dt got(int now,int l,int r,int x,int y)
{
if(x<=l&&y>=r)return maxn[now];
int mid=l+r >>1,ls=now<<1,rs=(now<<1)|1;
dt ans=(dt){-1,-1000000000,-1000000001};
if(x<=mid)ans=MAX(ans,got(ls,l,mid,x,y));
if(y>mid)ans=MAX(ans,got(rs,mid+1,r,x,y));
return ans;
}
int nn[222222],las[222222];
int in[222222],out[222222];
int Time=0;
void dfs(int x)
{
in[x]=++Time;
newid[Time]=x;
for(int y=las[x];y;y=nn[y])
dfs(y);
out[x]=Time;
}
int main()
{
freopen("soldier.in","r",stdin);
freopen("soldier.out","w",stdout);
int i,x,n,q;
scanf("%d%d",&n,&q);
for(i=2;i<=n;i++)
scanf("%d",&x),nn[i]=las[x],las[x]=i;
dfs(1);
for(i=1;i<=n;i++)
scanf("%d%d",&b[i],&l[i]);
init(1,1,n);
frl[0]=bel[n+1]=(node){0,-1000000000};
for(i=1;i<=n;i++)
frl[i]=MEX(frl[i-1],(node){l[newid[i]],-1000000000});
for(i=n;i;--i)
bel[i]=MEX(bel[i+1],(node){l[newid[i]],-1000000000});
while(q--)
{
scanf("%d",&x);
node can=MEX(frl[in[x]-1],bel[out[x]+1]);
dt ans=got(1,1,n,in[x],out[x]);
if(ans.v1<0)puts("0");
else{
if(ans.v1+can.v0==ans.v0)printf("%d\n",max(ans.v1+can.v1,ans.v2+can.v0));
else printf("%d\n",min(ans.v1+can.v0,ans.v0));
}
}
return 0;
}
/*
*/
这就完了?还没有
以上代码是本蒟蒻在神志不清的时候打的,实际上根本不用线段树
DFS一下,合并即可
#include <stdio.h>
#include <iostream>
using namespace std;
struct dt{
int v0,v1,v2;
}ans[1110000];
struct node{
int v0,v1;
}frl[222222],bel[222222];
int l[222222];
int newid[222222];
node MEX(node a,node b)
{
node ans;
ans.v0=max(a.v0,b.v0);
ans.v1=a.v1;
if(a.v0<ans.v0)ans.v1=max(ans.v1,a.v1);
if(b.v0<ans.v0)ans.v1=max(ans.v1,b.v0);
if(b.v1<ans.v0)ans.v1=max(ans.v1,b.v1);
return ans;
}
dt MAX(dt a,dt b)
{
dt ans;
if(a.v0>b.v0)
{
ans.v0=a.v0;
ans.v1=max(a.v1,b.v0);
ans.v2=a.v2;
if(a.v1<ans.v1)ans.v2=max(ans.v2,a.v1);
if(b.v0<ans.v1)ans.v2=max(ans.v2,b.v0);
if(b.v1<ans.v1)ans.v2=max(ans.v2,b.v1);
if(b.v2<ans.v2)ans.v2=max(ans.v2,b.v2);
}
else{
ans.v0=b.v0;
ans.v1=max(b.v1,a.v0);
ans.v2=b.v2;
if(b.v1<ans.v1)ans.v2=max(ans.v2,b.v1);
if(a.v0<ans.v1)ans.v2=max(ans.v2,a.v0);
if(a.v1<ans.v1)ans.v2=max(ans.v2,a.v1);
if(a.v2<ans.v2)ans.v2=max(ans.v2,a.v2);
}
return ans;
}
int nn[222222],las[222222];
int in[222222],out[222222];
int Time=0;
void dfs(int x)
{
in[x]=++Time;
newid[Time]=x;
for(int y=las[x];y;y=nn[y])
{
dfs(y);
ans[x]=MAX(ans[x],ans[y]);
}
out[x]=Time;
}
int main()
{
int i,x,n,q;
scanf("%d%d",&n,&q);
for(i=2;i<=n;i++)
scanf("%d",&x),nn[i]=las[x],las[x]=i;
for(i=1;i<=n;i++)
scanf("%d%d",&ans[i].v0,&l[i]),ans[i].v1=-1000000000,ans[i].v2=-1000000001;
dfs(1);
frl[0]=bel[n+1]=(node){0,-1000000000};
for(i=1;i<=n;i++)
frl[i]=MEX(frl[i-1],(node){l[newid[i]],-1000000000});
for(i=n;i;--i)
bel[i]=MEX(bel[i+1],(node){l[newid[i]],-1000000000});
while(q--)
{
scanf("%d",&x);
node can=MEX(frl[in[x]-1],bel[out[x]+1]);
dt as=ans[x];
if(as.v1<0)puts("0");
else{
if(as.v1+can.v0==as.v0)printf("%d\n",max(as.v1+can.v1,as.v2+can.v0));
else printf("%d\n",min(as.v1+can.v0,as.v0));
}
}
return 0;
}