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

超级钢琴放到了树上。

这次不用主席树了..本来以为会好写一点没想到细节更多(其实是树上细节多)

为了方便,对每个点把他的那个L,R区间转化成两个深度a,b,表示从[a,b)选一个最小的前缀和(到根的和)减掉

为了更加方便,编号变为2~N+1,然后把2连到1上,1作为一个假根,权值为0

然后倍增去找那个a和b,记一记最小值的位置,然后劈开再加回到优先队列里就行了

 1 #include<bits/stdc++.h>
 2 #define pa pair<int,int>
 3 #define CLR(a,x) memset(a,x,sizeof(a))
 4 using namespace std;
 5 typedef long long ll;
 6 const int maxn=5e5+10;
 7 const ll inf=1e12;
 8 
 9 inline ll rd(){
10     ll x=0;char c=getchar();int neg=1;
11     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
12     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
13     return x*neg;
14 }
15 
16 struct Node{
17     int x,l,r,m;ll v;
18 };
19 bool operator < (Node a,Node b){return a.v<b.v;}
20 bool operator > (Node a,Node b){return a.v>b.v;}
21 int N,M,L,R;
22 int fa[maxn][22],mi[maxn][22],dep[maxn];
23 ll mn[maxn][22],v[maxn];
24 priority_queue<Node> q;
25 
26 inline ll getrmq(int x,int l,int r,int &m){
27     if(l<=0) return -inf;
28     ll vx=v[x];
29     for(int i=19;i>=0;i--){
30         if(fa[x][i]&&dep[fa[x][i]]>=l)
31             x=fa[x][i];
32     }
33     ll f=inf;
34     for(int i=19;i>=0;i--){
35         if(fa[x][i]&&dep[fa[x][i]]>=r){
36             if(mn[x][i]<f) f=mn[x][i],m=dep[mi[x][i]];
37             x=fa[x][i];
38         }
39     }
40     if(dep[x]>r&&mn[x][0]<f) f=mn[x][0],m=dep[mi[x][0]];
41     // printf("%d %d\n",vx,f);
42     return vx-f;
43 }
44 
45 int main(){
46     //freopen("","r",stdin);
47     int i,j,k;
48     N=rd();
49     for(i=2;i<=N+1;i++){
50         fa[i][0]=rd()+1;
51     }dep[1]=1;
52     for(i=2;i<=N+1;i++) v[i]=v[fa[i][0]]+rd(),dep[i]=dep[fa[i][0]]+1;
53     M=rd(),L=rd(),R=rd();
54 
55     for(i=1;i<=N+1;i++){
56         mn[i][0]=v[i],mi[i][0]=i;
57         for(j=0;fa[i][j]&&fa[fa[i][j]][j];j++){
58             fa[i][j+1]=fa[fa[i][j]][j];
59             if(mn[i][j]<mn[fa[i][j]][j]) mn[i][j+1]=mn[i][j],mi[i][j+1]=mi[i][j];
60             else mn[i][j+1]=mn[fa[i][j]][j],mi[i][j+1]=mi[fa[i][j]][j];
61         }
62     }
63     for(i=2;i<=N+1;i++){
64         Node p;
65         p.x=i,p.l=dep[i]-L,p.r=dep[i]-R-1;
66         // printf("%d %d %d\n",p.x,p.l,p.r);
67         if(p.l<=0) continue;
68         p.v=getrmq(p.x,p.l,p.r,p.m);
69         q.push(p);
70     }
71     ll ans=0;
72     for(i=1;i<=M;i++){
73         Node p=q.top();q.pop();
74         ans+=p.v;
75         if(p.m<p.l){
76             Node p1;
77             p1.x=p.x,p1.l=p.l,p1.r=p.m;
78             p1.v=getrmq(p1.x,p1.l,p1.r,p1.m);
79             q.push(p1);
80         }if(p.r<p.m-1){
81             Node p2;
82             p2.x=p.x,p2.l=p.m-1,p2.r=p.r;
83             p2.v=getrmq(p2.x,p2.l,p2.r,p2.m);
84             q.push(p2);
85         }
86     }
87     printf("%lld\n",ans);
88     return 0;
89 }

 

转载于:https://www.cnblogs.com/Ressed/p/9758745.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值