题面

Description

身为IOI金牌的gtyzs有自己的一个OJ,名曰GOJ。GOJ上的题目可谓是高质量而又经典,他在他的OJ里面定义了一个树形的分类目录,且两个相同级别的目录是不会重叠的。比如图论的大目录下可能分为最短路,最小生成树,网络流等低一级的分类目录,这些目录下可能还有更低一级的目录,以此类推。现在gtyzs接到了一个任务,要他为SDTSC出题。他准备在自己的OJ题库中找出M道题作为SDTSC的试题,而他深知SDTSC的童鞋们个个都是神犇,所以gtyzs认为自己出的这M道题中,每道题都应该属于不少于L种分类目录;可他又怕自己的题没有人会做,所以每道题也应该属于不超过R种分类目录,并且这些分类目录应该是连续的,不能出现断层。对了,最重要的是,不存在一道题,它属于两个分类目录且这两个目录不是包含关系。(比如不存在一道题它既是一道DP题,又是一道网络流题)gtyzs怕被骂,所以他希望不存在任意的一对题目(u,v),使得u所属的分类目录与v完全相同。举例来说,gtyzs不能出两道同样的都是动态规划,背包的题,但是却可以出一道属于动态规划,背包和01背包的题和一道属于背包,01背包的题,当然也可以出一个属于图论的题和一个属于数论的题。(注意:一道题所属的分类目录不一定从根开始,如加粗部分所示)

为了让自己的题目变得更加靠谱,他给每一个分类目录都定了一个靠谱值ai,这个值可正可负。一道题的靠谱度为其从属的分类目录靠谱值的加和。我们假设动态规划的靠谱值为10,插头DP的靠谱值为-5,则一道动态规划插头DP的题的靠谱值就是5。gtyzs希望自己出的这M道题,在满足上述前提条件下,靠谱度总和最大。gtyzs当然会做啦,于是你就看到了这个题。

Input

输入的第一行是一个正整数N,代表分类目录的总数。

接下来的一行,共N个正整数,第i个正整数为fi,表示分类目录i被fi所包含。保证一个分类目录只会被一个分类目录所包含,且包含关系不存在环。特别的,fi=0表示它是根节点,我们保证这样的点只存在一个。

接下来的一行,共N个整数,第i个数表示ai。

最后一行,三个正整数M,L,R。

对于100%的数据,1≤N≤500,000,1≤M≤500,000,|ai|≤2,000。保证输入数据有解。

为了方便,所有的测试数据中都有f1=0,且对于任意的i∈[2,N],有fi<i。

Output

一行一个整数,表示最大的靠谱度。

Sample Input

7

0 1 1 2 2 3 3

2 3 4 1 2 3 4

3 3 3

Sample Output

26


简化版本

这题的简化版本:https://www.lydsy.com/JudgeOnline/problem.php?id=2006

我们可以从最大的开始枚举\(k\)个可行区间。

我们用五个信息来维护区间\((x,l,r,q,v)\),\(x\)表示区间右端点,\(l\)表示区间最左边可以到的位置,\(r\)表示区间最右边可以到的位置,\(q\)表示最大区间和在的左边界坐标,\(v\)表示这个可行范围内的最大区间和。

我们先枚举所有的右边界,直接扔到优先队列里维护\(v\)即可。

对于当前取出的区间,我们可以把它分裂成两个区间\((x,l,q-1,q_1,v_1)\),\((x,q+1,r,q_2,v_2)\),即区间位置\(q\)以后的区间,\(q_1,1_2,v_1,v_2\)需要重新计算。

int n,m,L,R,a[500010],f[500010][35],ans[500010];
struct data
{
int x,l,r,p,v;
data(int a=0,int b=0,int c=0,int d=0,int e=0):x(a),l(b),r(c),p(d),v(e){};
};
struct cmp
{
bool operator()(data x,data y)
{
return x.v<y.v;
}
};
priority_queue<data,vector<data>,cmp> q; void init()
{
for (int i=0;i<=n;i++)
f[i][0]=a[i];
for (int i=1;(1<<i)<=n+1;i++)
for (int j=0;j+(1<<i)-1<=n+1;j++)
f[j][i]=min(f[j][i-1],f[j+(1<<(i-1))][i-1]);
} int query(int l,int r)
{
int k=(int)(log(double(r-l+1))/log((double)2));
return min(f[l][k],f[r-(1<<k)+1][k]);
} int calc(int l,int r)
{
int mid,res,x=query(l,r);
while(l<=r)
{
mid=l+r>>1;
if (query(mid,r)<=x) res=mid,l=mid+1;else r=mid-1;
}
return res;
} int main()
{
scanf("%d%d%d%d",&n,&m,&L,&R);
a[0]=0;
for (int i=1;i<=n;i++)
scanf("%d",&a[i]),a[i]+=a[i-1];
init();
for (int i=L;i<=n;i++)
{
int l=max(i-R,0),r=i-L;
q.push(data(i,l,r,calc(l,r),a[i]-query(l,r)));
//printf("%d %d %d %d %d\n",i,l,r,calc(l,r),a[i]-query(l,r));
}
LL ans=0;
//cout<<q.size<<endl;
while(m--)
{
if (q.empty()) break;
int x=q.top().x,l=q.top().l,r=q.top().r,p=q.top().p;
//cout<<q.top().v<<endl;
ans+=(LL)q.top().v;
q.pop();
if (p-1>=l) q.push(data(x,l,p-1,calc(l,p-1),a[x]-query(l,p-1)));
//printf("%d %d %d %d %d\n",x,l,p-1,calc(l,p-1),a[x]-query(l,p-1));
if (r>=p+1) q.push(data(x,p+1,r,calc(p+1,r),a[x]-query(p+1,r)));
//printf("%d %d %d %d %d\n",x,p+1,r,calc(p+1,r),a[x]-query(p+1,r));
}
cout<<ans<<endl;
return 0;
}

分析

作为上边的加强版,我们只要从叶子结点开始统计\(min\)信息和\(fa\)信息,然后把所有结点作为最底层结点,向上维护,类似于链的形式,维护一个五元的组合。

noi的钢琴那题,贪图方便,上面那份代码时间复杂度是\(O(n\times log^2_2m)\),然后这题就被卡了。

在维护st表的时候,新开一个数组\(ANS\)表示当前位置向上对应的长度,然后不再用二分去探查位置,直接可以得到。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<string>
#include<climits>
#include<vector>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<ctime>
#define LL long long
#define inf 0x3f3f3f3f using namespace std; inline char nc(){
/*
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
*/return getchar();
} inline void read(int &x){
char c=nc();int b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
} inline void read(LL &x){
char c=nc();LL b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
} inline void read(char &x){
for (x=nc();!(x=='('||x==')');x=nc());
} inline int read(char *s)
{
char c=nc();int len=1;
for(;!(c=='('||c==')');c=nc()) if (c==EOF) return 0;
for(;(c=='('||c==')');s[len++]=c,c=nc());
s[len++]='\0';
return len-2;
}
int wt,ss[19];
inline void print(int x){
if (x<0) x=-x,putchar('-');
if (!x) putchar(48); else {
for (wt=0;x;ss[++wt]=x%10,x/=10);
for (;wt;putchar(ss[wt]+48),wt--);}
}
inline void print(LL x){
if (x<0) x=-x,putchar('-');
if (!x) putchar(48); else {for (wt=0;x;ss[++wt]=x%10,x/=10);for (;wt;putchar(ss[wt]+48),wt--);}
} int n,m,L,R,S,a[500010],c[500010],h[500010],to[1000010],ne[1000010],d[500010];
int p[1000010][40],f[1000010][40],ANS[1000010][40];
struct data
{
int x,l,r,p,v;
data(int a=0,int b=0,int c=0,int d=0,int e=0):x(a),l(b),r(c),p(d),v(e){};
};
struct cmp
{
bool operator()(data x,data y)
{
return x.v<y.v;
}
};
priority_queue<data,vector<data>,cmp> q; void dfs(int u)
{
c[u]=1;
for (int i=h[u];i!=-1;i=ne[i])
{
if (!d[to[i]])
{
d[to[i]]=d[u]+1;
p[to[i]][0]=u;
a[to[i]]+=a[u];
dfs(to[i]);
//a[u]+=a[to[i]];
c[u]+=c[to[i]];
}
}
} void init()
{
for (int i=0;i<=n;i++)
f[i][0]=a[i],ANS[i][0]=0;
p[1][0]=0;
for (int j=1;(1<<j)<=n+1;j++)
for (int i=0;i<=n;i++)
if (p[i][j-1]!=-1)
{
p[i][j]=p[p[i][j-1]][j-1];
if (f[i][j-1]<=f[p[i][j-1]][j-1]) ANS[i][j]=ANS[i][j-1];
else ANS[i][j]=ANS[p[i][j-1]][j-1]+((1<<(j-1)));
f[i][j]=min(f[i][j-1],f[p[i][j-1]][j-1]); //cout<<i<<" "<<j<<" "<<ANS[i][j]<<" "<<f[i][j]<<endl;
}
} void Add(int x,int y)
{
S++;to[S]=x;ne[S]=h[y];h[y]=S;
S++;to[S]=y;ne[S]=h[x];h[x]=S;
} int Find(int x,int y)
{
y=d[x]-y;
int i;
for (i=0;(1<<i)<=d[x];i++);i--;
for (int j=i;j>=0;j--)
if (d[x]-(1<<j)>=y) x=p[x][j];
return x;
} int query(int x,int l,int r)
{
int k=(int)(log(double(r-l+1))/log((double)2));
return min(f[Find(x,l)][k],f[Find(x,r-(1<<k)+1)][k]);
} int calc(int x,int l,int r)
{
int k=(int)(log(double(r-l+1))/log((double)2));
int y=Find(x,l),z=Find(x,r-(1<<k)+1);
//printf("%d %d %d %d\n",y,k,z,k);
if (f[y][k]<=f[z][k]) return ANS[y][k]+l;else return ANS[z][k]+(r-(1<<k)+1);
} int main()
{
freopen("3","r",stdin);
read(n);
memset(h,-1,sizeof(h));
memset(d,0,sizeof(d));
memset(p,-1,sizeof(p));
S=0;
int x,y;
for(int i=1;i<=n;i++)
{
read(x);
if (x>0) Add(x,i);
}
for (int i=1;i<=n;i++)
read(a[i]);
d[1]=1;dfs(1);
init();
read(m);read(L);read(R);
for (int i=1;i<=n;i++)
if (d[i]>=L)
{
int l=L,r=min(R,d[i]);
q.push(data(i,l,r,calc(i,l,r),a[i]-query(i,l,r)));
//printf("%d %d %d %d %d\n",i,l,r,calc(i,l,r),a[i]-query(i,l,r));
}
//return 0;
LL ans=0;
while(m--)
{
if (q.empty()) break;
data z=q.top();
int x=z.x,l=z.l,r=z.r,p=z.p;
//cout<<q.top().v<<endl;
ans+=(LL)z.v;
//cout<<l<<" "<<p<<endl;
q.pop();
if (p-1>=l) q.push(data(x,l,p-1,calc(x,l,p-1),a[x]-query(x,l,p-1)));
//printf("%d %d %d %d %d\n",x,l,p-1,calc(x,l,p-1),a[x]-query(x,l,p-1));
if (r>=p+1) q.push(data(x,p+1,r,calc(x,p+1,r),a[x]-query(x,p+1,r)));
//printf("%d %d %d %d %d\n",x,p+1,r,calc(x,p+1,r),a[x]-query(x,p+1,r));
}
print(ans),puts("");
return 0;
}

【BZOJ4458】GTY的OJ的更多相关文章

  1. 【贪心 计数 倍增】bzoj4458: GTY的OJ

    倍增写挂调了半个晚上 Description 身为IOI金牌的gtyzs有自己的一个OJ,名曰GOJ.GOJ上的题目可谓是高质量而又经典,他在他的OJ里面定义了一个树形的分类目录,且两个相同级别的目录 ...

  2. bzoj4458: GTY的OJ

    题目大意:给定一棵带点权的有根树,同时给定L,R,要求找M条链,每条链满足以下条件的情况下,要求所有链权和最大: 1.两两不相同(可以包含/相交等) 2.节点数在[L,R]间 3.其中一个端点的深度必 ...

  3. bzoj4458 GTY的OJ (优先队列+倍增)

    把超级钢琴放到了树上. 这次不用主席树了..本来以为会好写一点没想到细节更多(其实是树上细节多) 为了方便,对每个点把他的那个L,R区间转化成两个深度a,b,表示从[a,b)选一个最小的前缀和(到根的 ...

  4. 【BZOJ4458】GTY的OJ(树上超级钢琴)

    点此看题面 大致题意: 给你一棵树,让你求出每一个节点向上的长度在\([l,r]\)范围内的路径权值和最大的\(m\)条路径的权值总和. 关于此题的数列版本 此题的数列版本,就是比较著名的[BZOJ2 ...

  5. 2018.10.29 NOIP2018模拟赛 解题报告

    得分: \(70+60+0=130\)(\(T3\)来不及打了,结果爆\(0\)) \(T1\):简单的求和(点此看题面) 原题: [HDU4473]Exam 这道题其实就是上面那题的弱化版,只不过把 ...

  6. NOIP2018赛前停课集训记(10.24~11.08)

    前言 为了不久之后的\(NOIP2018\),我们的停课从今天(\(Oct\ 24th\))起正式开始了. 本来说要下周开始的,没想到竟提早了几天,真是一个惊喜.毕竟明天有语文考试.后天有科学考试,逃 ...

  7. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  8. Online Judge(OJ)搭建(第一版)

    搭建 OJ 需要的知识(重要性排序): Java SE(Basic Knowledge, String, FileWriter, JavaCompiler, URLClassLoader, Secur ...

  9. [BZOJ3729]Gty的游戏

    [BZOJ3729]Gty的游戏 试题描述 某一天gty在与他的妹子玩游戏.妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问将某个节点的子树中的石子移动 ...

随机推荐

  1. Python编码、流程控制、格式化输出

    Python编码 初始编码: 电脑的传输,还有储存,实际上都是010101010 ASCII码: (American Standard Code for Information Interchange ...

  2. 团队冲刺Alpha(七)

    目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...

  3. 个人支付宝监控并自动获取交易记录对接系统API

    我们都知道,支付宝支付API接口只有企业才能使用,但有一部分业务,可能我们不方便使用企业收款,但又想做到自动化,那怎么办呢 于是一个支付宝交易记录自动监控软件诞生了. 支付宝都有一个收款二维码,收款提 ...

  4. PHP实现图片上传并压缩

    本文实例讲解了PHP图片上传并压缩的实现方法,分享给大家供大家参考,具体内容如下 使用到三个文件 connect.php:连接数据库 test_upload.php:执行SQL语句 upload_im ...

  5. [LOJ#6259]「CodePlus 2017 12 月赛」白金元首与独舞

    [LOJ#6259]「CodePlus 2017 12 月赛」白金元首与独舞 试题描述 到河北省 见斯大林 / 在月光下 你的背影 / 让我们一起跳舞吧 うそだよ~ 河北省怎么可能有 Stalin. ...

  6. POJ 2195 Going Home | 带权二分图匹配

    给个地图有人和房子 保证人==房子,每个人移动到房子处需要花费曼哈顿距离的代价 问让人都住在房子里最小代价 显然是个带权二分图最大匹配 转化成以一个网络,规定w是容量,c是代价 1.S向人连边,w=1 ...

  7. php中json_encode和json_decode的用法

    1.json_encode基本用法:数组转字符串 <?php $arr = array ('a'=>1,'b'=>2,'c'=>3,'d'=>4,'e'=>5); ...

  8. linux上的vim永久显示行号

    步骤1: cp /usr/share/vim/vimrc ~/.vimrc 先复制一份vim配置模板到个人目录下 注:redhat 改成 cp /etc/vimrc ~/.vimrc 步骤2: vi ...

  9. angular.extend(dst,src)的简单示例

    自我认为这个方法跟angular.copy(src,dst)有点相似.在angular.extend({},src)时,就可以画等号.这个src只代表一个对象.代码如下:(注意这个src可以有多个对象 ...

  10. hdu 1847 Good Luck in CET-4 Everybody! SG函数SG引理

    大学英语四级考试就要来临了,你是不是在紧张的复习?也许紧张得连短学期的ACM都没工夫练习了,反正我知道的Kiki和Cici都是如此.当然,作为在考场浸润了十几载的当代大学生,Kiki和Cici更懂得考 ...