题目概述
有
n
个目录,每个目录有一个父亲目录和靠谱值,一个题目由若干个目录构成,其中任何一个目录都是别的目录的子孙和祖先,一个题目的靠谱值是所有目录靠谱值的和。需要选
解题报告
和BZOJ2006套路是一样的,只不过做到了树上。
所以我们使用树上RMQ就行了。
示例程序
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=500000,Log=19;
int n,K,L,R,sum[maxn+5];
int dep[maxn+5],fa[maxn+5][Log+5],RMQ[maxn+5][Log+5];
LL ans;
inline bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}
inline char readc()
{
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; else return *l++;
}
inline int readi(int &x)
{
int tot=0,f=1;char ch=readc(),lst='+';
while ('9'<ch||ch<'0') {if (ch==EOF) return EOF;lst=ch;ch=readc();}
if (lst=='-') f=-f;
while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=readc();
return x=tot*f,Eoln(ch);
}
int Miner(int i,int j) {if (sum[fa[i][0]]<sum[fa[j][0]]) return i; else return j;}
void make_ST()
{
for (int j=1;j<=Log;j++)
for (int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
for (int j=1;j<=Log;j++)
for (int i=1;i<=n;i++) if (dep[i]>=(1<<j))
RMQ[i][j]=Miner(RMQ[i][j-1],RMQ[fa[i][j-1]][j-1]);
}
struct data
{
int i,L,R,t;
data(int a,int b,int c,int d) {i=a;L=b;R=c;t=d;}
bool operator < (const data &c) const
{return sum[i]-sum[fa[t][0]]<sum[c.i]-sum[fa[c.t][0]];}
};
priority_queue<data> Heap;
int Askfa(int x,int len)
{
for (int j=Log;j>=0;j--)
if (len&(1<<j)) x=fa[x][j],len-=1<<j;
return x;
}
int Askmax(int x,int y)
{
int MIN=RMQ[x][0];
for (int j=Log;j>=0;j--)
if (dep[fa[y][j]]>=dep[x]) MIN=Miner(MIN,RMQ[y][j]),y=fa[y][j];
return MIN;
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
readi(n);
for (int i=1;i<=n;i++) readi(fa[i][0]);
for (int i=1,x;i<=n;i++)
{
readi(x);sum[i]=sum[fa[i][0]]+x;
dep[i]=dep[fa[i][0]]+1;RMQ[i][0]=i;
}
make_ST();readi(K);readi(L);readi(R);
for (int i=1;i<=n;i++) if (dep[i]>=L)
{
int l=max(1,Askfa(i,R-1)),r=Askfa(i,L-1);
Heap.push(data(i,l,r,Askmax(l,r)));
}
while (K--)
{
data now=Heap.top();Heap.pop();ans+=sum[now.i]-sum[fa[now.t][0]];
if (now.t!=now.L)
{
int ft=fa[now.t][0];
Heap.push(data(now.i,now.L,ft,Askmax(now.L,ft)));
}
if (now.t!=now.R)
{
int len=dep[now.i]-dep[now.t],st=Askfa(now.i,len-1);
Heap.push(data(now.i,st,now.R,Askmax(st,now.R)));
}
}
printf("%lld\n",ans);
return 0;
}