【巴蜀】士兵训练

题目描述

在 C 国中有 n 位士兵,除士兵 1 外,每位士兵 i 均有且仅有一位士兵 j j < i 作为他的直属教官。士兵 i 被他的直属教官 j 以及所有能管辖 j 的士兵所管辖。每位士兵也看做能管辖自己。
每位士兵均有两个属性值:战斗力 b i 与领导力 l i
现在 C 国要举行 q 次阅兵,每次阅兵会指定一位士兵 s 做总指挥,士兵 s需要训练自己所管辖的所有士兵,并以最好的精神面貌迎接阅兵式。
士兵 s 每次阅兵训练时有一次机会(只能使用一次或不使用),可以邀请一位不受他管辖的士兵 i 来指导一位他所管辖的士兵 j,并会使得士兵 j 的战斗力由 b j 提升为 b j + l i ,这次提升仅对当次阅兵有效。
士兵 s 训练出的士兵队伍所能展现出的精神力 P 为: M a x { b i % b j },i、j 被s管辖
现在 C 国主席想知道,每次阅兵的队伍所能展现出的精神力 P 最大能是多少?请你帮助他。

输入格式

第一行两个数 n,q 表示士兵数以及阅兵次数。
接下来一行 n-1 个整数,第 i 个整数表示士兵 i+1 的直属教官。
接下来 n 行每行两个整数 b i l i 描述一位士兵的属性。
接下来 q 行每行一个整数 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的子树中的一个点加上某一权值(也可以不加),求不同方法更新后的子树严格次大值的最大值。
我们记录子树中原来的战斗力最大值、次大值、第三大值分别为 b 0 b 1 b 2 ,子树外的领导力最大值、次大值为 l 0 l 1 。要求 b 0 b 1 b 1 > b 2 l 0 > l 1
b 1 + l 0 b 0 时,显然 b 1 加上 l 0 是最优的
b 1 + l 0 = b 0 时,显然不能这样加(否则mod出来是0)。于是就有两种可能的答案: b 1 + l 1 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;
}

猜你喜欢

转载自blog.csdn.net/includelhc/article/details/81779245