线段树 BZOJ3252 攻略

3252: 攻略

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 496  Solved: 211
[Submit][Status][Discuss]

Description

题目简述:树版[k取方格数]

众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏。

今天他得到了一款新游戏《XX半岛》,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景。所有场景和选择支构成树状结构:开始游戏时在根节点(共通线),叶子节点为结局。每个场景有一个价值,现在桂马开启攻略之神模式,同时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的)

“为什么你还没玩就知道每个场景的价值呢?”

“我已经看到结局了。”

Input

第一行两个正整数n,k

第二行n个正整数,表示每个场景的价值

以下n-1行,每行2个整数a,b,表示a场景有个选择支通向b场景(即a是b的父亲)

保证场景1为根节点

Output

输出一个整数表示答案

Sample Input

5 2

4 3 2 1 1

1 2

1 5

2 3

2 4

Sample Output

10

HINT

对于100%的数据,n<=200000,1<=场景价值<=2^31-1

dfs序+线段树的模板吧……

函数传参不要写错!!!!!!

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 #define inf 1000000000000000ll
  7 int n,k,cnt,tot;
  8 long long ans;
  9 long long val[200010],sum[200010];
 10 int head[200010],getin[200010],getout[200010],oula[200010],fa[200010];
 11 bool check[200010];
 12 struct data{
 13     int next,to;
 14 }edge[400010];
 15 struct dt{
 16     long long mx,loc,tag;
 17 }segtree[800010];
 18 void add(int start,int end){
 19     edge[++cnt].next=head[start];
 20     edge[cnt].to=end;
 21     head[start]=cnt;
 22     fa[end]=start;
 23 }
 24 void dfs(int u){
 25     getin[u]=++tot;
 26     oula[tot]=u;
 27     for(int i=head[u];i;i=edge[i].next){
 28         sum[edge[i].to]=sum[u]+val[edge[i].to];
 29         dfs(edge[i].to);
 30     }
 31     getout[u]=tot;
 32 }
 33 void up(int pos){
 34     segtree[pos].mx=0;
 35     if(segtree[pos<<1].mx>segtree[pos].mx){
 36         segtree[pos].mx=segtree[pos<<1].mx;
 37         segtree[pos].loc=segtree[pos<<1].loc;
 38     }
 39     if(segtree[pos<<1|1].mx>segtree[pos].mx){
 40         segtree[pos].mx=segtree[pos<<1|1].mx;
 41         segtree[pos].loc=segtree[pos<<1|1].loc;
 42     }
 43 }
 44 void build(int pos,int ll,int rr){
 45     if(ll==rr){
 46         segtree[pos].mx=sum[oula[ll]];
 47         segtree[pos].loc=ll;
 48         return;
 49     }
 50     int mid=(ll+rr)>>1;
 51     build(pos<<1,ll,mid);
 52     build(pos<<1|1,mid+1,rr);
 53     up(pos);
 54 }
 55 void update(int pos,long long dd){//!!!!!!!!!!!!!!!!!!!!!!!! long long
 56     segtree[pos].mx-=dd;
 57     segtree[pos].tag+=dd;
 58 }
 59 void down(int pos){
 60     if(!segtree[pos].tag) return;
 61     update(pos<<1,segtree[pos].tag);
 62     update(pos<<1|1,segtree[pos].tag);
 63     segtree[pos].tag=0;
 64     return;
 65 }
 66 void change(int pl,int pr,long long dd,int pos,int ll,int rr){
 67     int mid=(ll+rr)>>1;
 68     if(pl>rr||pr<ll) return;
 69     if(pl<=ll&&pr>=rr){
 70         update(pos,dd);
 71         return;
 72     }
 73     down(pos);
 74     if(pr<=mid) change(pl,pr,dd,pos<<1,ll,mid);
 75     else if(pl>mid) change(pl,pr,dd,pos<<1|1,mid+1,rr);
 76     else{
 77         change(pl,mid,dd,pos<<1,ll,mid);
 78         change(mid+1,pr,dd,pos<<1|1,mid+1,rr);
 79     }
 80     up(pos);
 81 }
 82 int main(){
 83     scanf("%d%d",&n,&k);
 84     for(int i=1;i<=n;i++) scanf("%lld",&val[i]);
 85     int x,y;
 86     for(int i=1;i<n;i++){
 87         scanf("%d%d",&x,&y);
 88         add(x,y);
 89     }
 90     sum[1]=val[1];
 91     dfs(1);
 92     build(1,1,n);
 93     for(int i=1;i<=k;i++){
 94         ans+=segtree[1].mx;
 95         for(int j=oula[segtree[1].loc];!check[j]&&j;j=fa[j]){
 96             check[j]=1;
 97             change(getin[j],getin[j],inf,1,1,n);//ll的极值???
 98             if(getin[j]<getout[j]) change(getin[j]+1,getout[j],val[j],1,1,n);
 99         }
100     }
101     printf("%lld",ans);
102     return 0;
103 }
时间: 2024-08-28 22:39:32

线段树 BZOJ3252 攻略的相关文章

BZOJ3252: 攻略 可并堆

网上有很多人说用dfs序+线段树做...其实stl的堆可以...可并堆可以...很多奇奇怪怪的东西都能做... 可并堆比较好想...也比较好写... 分析: 首先,这是一个网络流做不了的题...数据太大... 其次...我们可以这样考虑一下,这个点的子树中,将这个点的权值仅更新给最大的那个就能满足 之后,在每一个叶子节点上,建立一个大根堆,dfs一遍,将子节点的堆合并,之后找到根节点,将根节点的权值加上当前位置的价值 最后,根节点中前k大的权值和即为答案... 附上代码,精简可行 #includ

BZOJ3252 攻略

Orz hzwer 只要用堆就可以了,跪烂了... 话说那个什么ext的库真的能用嘛= =,反正我用了烂删除 结果Rank.3←_← 1 /************************************************************** 2 Problem: 3252 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:964 ms 7 Memory:14036 kb 8 *****************

【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心

3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 130[Submit][Status][Discuss] Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛>,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景.所有场景和选择支构成树状结构:开始游戏时在根节点(共通线)

【Bzoj3252】攻略(dfs序+线段树)

Description 题目链接 Solution 可以想到,每次肯定是拿最大价值为最优 考虑改变树上一个点的值,只会影响它的子树,也就是dfs序上的一个区间, 于是可以以dfs序建线段树,这样就变成区间问题了 Code #include <cstdio> #include <algorithm> #define MID int mid=(l+r)>>1,ls=id<<1,rs=id<<1|1 #define ll long long #defi

BZOJ_3252_攻略_线段树+dfs序

Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏<XX 半岛>,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景.所有场景和选择支构成树状 结构:开始游戏时在根节点(共通线),叶子节点为结局.每个场景有一个价值,现在桂马开启攻略之神模式,同 时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的) “为什么你还没玩就知道每个场景的价

BZOJ 3252 攻略 线段树

题意:链接 方法:线段树 解析: 闲的随机的题. 看完题后看着好像挺简单的. 既然每个点的权值只会传子树,并且整个图是严格的一棵树,所以应该是跟dfs序有关. 然后去看数据范围. 尼玛HINT是什么鬼. 既然这么说了那就想想怎么做吧=-= 并且因为价值都为正的,所以显然要考虑贪心,挑k条从叶节点到根的所有点权值和最大的k条. 并且每一挑完后都需要更新. 然后有一个性质,每个点至多选一次,也就是说每个点至多被删一次. 并且根节点到叶节点链上的所有点的路径上的点权和是随着深度递增的. 所以显然我们用

Dfs【bzoj3252】攻略

Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛>,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景.所有场景和选择支构成树状结构:开始游戏时在根节点(共通线),叶子节点为结局.每个场景有一个价值,现在桂马开启攻略之神模式,同时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的) "为什么你还没玩就知道每个场

【贪心】 BZOJ 3252:攻略

3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 261  Solved: 90[Submit][Status][Discuss] Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛>,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景.所有场景和选择支构成树状结构:开始游戏时在根节点(共通线),

SPOJ--K-query (线段树离线) 离线操作解决一下问题

K-query Given a sequence of n numbers a1, a2, ..., an and a number of k- queries. A k-query is a triple (i, j, k) (1 ≤ i ≤ j ≤ n). For each k-query (i, j, k), you have to return the number of elements greater than k in the subsequence ai, ai+1, ...,