Description
Input
第一行两个数n,q 表示士兵数以及阅兵次数。
接下来一行n-1 个整数,第i 个整数表示士兵i+1 的直属教官。
接下来n 行每行两个整数i i b ,l 描述一位士兵的属性。
接下来q 行每行一个整数i s ,表示这次阅兵的总指挥。
Output
对于每次阅兵输出一行一个整数,表示阅兵队伍能展现出的最大精神力P。
Sample Input
输入1:
5 2
1 1 2 2
2 1
1 5
4 2
2 3
3 1
1
2
输入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
Sample Output
输出1:
3
3
样例1 解释:
第一次阅兵时无法进行指导
第二次阅兵时令士兵3 指导士兵4
输出2:
4
3
5
Data Constraint
30%的数据:n,q≤30
另有10%的数据:所有Si 均为1
另有20%的数据:q≤50
另有20%的数据:士兵i 的直属教官为i-1
100%的数据: 1<=n,q<=2*10^5,0<=bi,li<=10^9,bi>=1,1<=Si<=n
Solution
这题的话我们需要处理一个点的子树内的问题,于是我们按照DFS序遍历一遍。
我们发现要使 P 值更大,肯定是让模数越大越好,同时被除数也要变大。
于是我们先考虑不让别的士兵“指导”的情况,那肯定是直接用次大值模最大值。
如果“指导”呢?先找出与答案有关的量:
设子树内b的最大值为 mx 、次大值为 mx1 、严格次大值为 ymx1 、严格第三大值为 ymx2 。
再设子树外 l 的最大值为 x ,严格次大值为 y 。
如果有
mx1+x<mx ,则答案就是 mx1+x (直接提升次大值)。如果有 mx1+x>mx ,则答案就为 mx (仍然直接提升次大值并当作模数)。
如果有 mx1+x=mx ,那么还要继续讨论:
取 mx1+y
取 ymx2+x
取 ymx1
将以上情况取最大值即可,上述的每个量都可以用线段树维护,
因为 DFS 序一定是连续的一段(非常繁杂~~~)。
注意若查询的点是叶子结点( size 为 1),那么要特判输出 0,因为自己模自己为 0 。
Code
#include<cstdio>
using namespace std;
const int N=2e5+1;
struct tree
{
int mx,mx1,ymx1,ymx2;
}f[N<<2];
struct data
{
int x,y;
}a[N],g[N<<2],null;
int tot;
int first[N],next[N],en[N];
int dfn[N],size[N],pre[N];
inline int read()
{
int X=0,w=1; char ch=0;
while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
return X*w;
}
inline void write(int x)
{
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline int max(int x,int y)
{
return x>y?x:y;
}
inline int min(int x,int y)
{
return x<y?x:y;
}
inline void insert(int x,int y)
{
next[++tot]=first[x];
first[x]=tot;
en[tot]=y;
}
inline void dfs(int x)
{
size[x]=1;
dfn[x]=++tot;
pre[tot]=x;
for(int i=first[x];i;i=next[i])
{
dfs(en[i]);
size[x]+=size[en[i]];
}
}
inline tree mergef(tree x,tree y)
{
tree z;
if(x.mx>y.mx)
{
z.mx=x.mx;
z.mx1=max(y.mx,x.mx1);
z.ymx1=max(y.mx,x.ymx1);
z.ymx2=x.ymx2;
if(x.ymx1>y.mx) z.ymx2=max(z.ymx2,y.mx);
if(x.ymx1<y.mx) z.ymx2=max(z.ymx2,max(x.ymx1,y.ymx1));
if(x.ymx1==y.mx) z.ymx2=max(z.ymx2,y.ymx1);
}else
if(x.mx<y.mx)
{
z.mx=y.mx;
z.mx1=max(x.mx,y.mx1);
z.ymx1=max(x.mx,y.ymx1);
z.ymx2=y.ymx2;
if(y.ymx1>x.mx) z.ymx2=max(z.ymx2,x.mx);
if(y.ymx1<x.mx) z.ymx2=max(z.ymx2,max(y.ymx1,x.ymx1));
if(y.ymx1==x.mx) z.ymx2=max(z.ymx2,x.ymx1);
}else
{
z.mx=z.mx1=x.mx;
z.ymx1=max(x.ymx1,y.ymx1);
if(x.ymx1^y.ymx1) z.ymx2=max(x.ymx2,y.ymx2); else
z.ymx2=min(x.ymx1,y.ymx1);
}
return z;
}
inline data mergeg(data x,data y)
{
data z;
if(x.x>y.x)
{
z.x=x.x;
z.y=max(y.x,x.y);
}else
if(x.x<y.x)
{
z.x=y.x;
z.y=max(x.x,y.y);
}else
{
z.x=x.x;
z.y=max(x.y,y.y);
}
return z;
}
inline void make(int v,int l,int r)
{
if(l==r)
{
f[v].mx=a[pre[l]].x;
g[v].x=a[pre[l]].y;
return;
}
int mid=(l+r)>>1,ls=v<<1l,rs=ls|1;
make(ls,l,mid);
make(rs,mid+1,r);
f[v]=mergef(f[ls],f[rs]);
g[v]=mergeg(g[ls],g[rs]);
}
inline tree findf(int v,int l,int r,int x,int y)
{
if(l>=x && r<=y) return f[v];
int mid=(l+r)>>1;
if(y<=mid) return findf(v<<1,l,mid,x,y);
if(x>mid) return findf(v<<1|1,mid+1,r,x,y);
return mergef(findf(v<<1,l,mid,x,mid),findf(v<<1|1,mid+1,r,mid+1,y));
}
inline data findg(int v,int l,int r,int x,int y)
{
if(x>y) return null;
if(l>=x && r<=y) return g[v];
int mid=(l+r)>>1;
if(y<=mid) return findg(v<<1,l,mid,x,y);
if(x>mid) return findg(v<<1|1,mid+1,r,x,y);
return mergeg(findg(v<<1,l,mid,x,mid),findg(v<<1|1,mid+1,r,mid+1,y));
}
int main()
{
int n=read(),q=read();
for(int i=2;i<=n;i++) insert(read(),i);
for(int i=1;i<=n;i++) a[i].x=read(),a[i].y=read();
tot=0,dfs(1);
make(1,1,n);
while(q--)
{
int s=read(),ans=0;
if(size[s]==1){puts("0");continue;}
tree tx=findf(1,1,n,dfn[s],dfn[s]+size[s]-1);
data ty=mergeg(findg(1,1,n,1,dfn[s]-1),findg(1,1,n,dfn[s]+size[s],n));
if(tx.mx1+ty.x<tx.mx) ans=tx.mx1+ty.x; else
if(tx.mx1+ty.x>tx.mx) ans=tx.mx; else
{
if(tx.mx1 && ty.y) ans=tx.mx1+ty.y;
if(tx.ymx2 && ty.x) ans=max(ans,tx.ymx2+ty.x);
if(tx.ymx1) ans=max(ans,tx.ymx1);
}
write(ans),putchar('\n');
}
return 0;
}