您的位置:首页 > 其它

【贪心】 BZOJ 3252:攻略

2015-12-29 18:47 423 查看

3252: 攻略

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 261 Solved: 90
[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

  很容易知道贪心策略:每次选价值最高的叶子节点

  但是貌似很难搞的样子

  朴素算法应该是n^2的样子。。

  O(n)显然不太好搞。。

  所以大约优化完后是O(nlgn)左右的复杂度。。

  有两种logn的方法

  1.黄学长的堆。。自行百度。。我只能说代码完全看不懂。。

  2.DFS序+线段树

  DFS处理出一个点管辖的所有点的DFS序。

  然后线段树添加,每次删除。

  





1 #include<cstdio>
2 #include<cstring>
3 #include<cmath>
4 #include<algorithm>
5 #include<vector>
6
7 #define maxn 200001
8
9 using namespace std;
10
11 vector<int>graph[maxn];
12
13 int rev[maxn],in[maxn],father[maxn],dfn[maxn],last[maxn],tot=0;
14
15 long long a[maxn];
16
17 bool vis[maxn];
18
19 struct tr{
20     int l,r,ps;
21     long long num,tag;
22 }tree[maxn*6];
23
24 long long read()
25 {
26     long long x=0;char ch=getchar();
27     while(ch<'0'||ch>'9')ch=getchar();
28     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
29     return x;
30 }
31
32 void DFS(int poi)
33 {
34     dfn[poi]=++tot;
35     rev[tot]=poi;
36     for(int i=graph[poi].size()-1;i>=0;i--)
37     {
38         int u=graph[poi][i];
39         DFS(u);
40     }
41     last[poi]=tot;
42 }
43
44 void psh(int poi)
45 {
46     if(tree[poi].tag&&tree[poi].l!=tree[poi].r)
47     {
48     tree[poi<<1].tag+=tree[poi].tag;
49     tree[(poi<<1)|1].tag+=tree[poi].tag;
50     tree[poi<<1].num+=tree[poi].tag;
51     tree[(poi<<1)|1].num+=tree[poi].tag;
52     tree[poi].tag=0;
53     }
54 }
55
56 void update(int num,int l,int r,long long d)
57 {
58     psh(num);
59     if(tree[num].l==l&&tree[num].r==r)
60     {
61         tree[num].num+=d;
62         tree[num].tag+=d;
63         return;
64     }
65     int mid=(tree[num].l+tree[num].r)>>1;
66     if(mid>=r)update(num<<1,l,r,d);
67     else if(l>mid)update((num<<1)|1,l,r,d);
68     else update(num<<1,l,mid,d),update((num<<1)|1,mid+1,r,d);
69     if(tree[num].l==tree[num].r)return;
70     if(tree[num<<1].num>tree[(num<<1)|1].num){tree[num].num=tree[num<<1].num,tree[num].ps=tree[num<<1].ps;}
71     if(tree[(num<<1)|1].num>=tree[num<<1].num){tree[num].num=tree[(num<<1)|1].num,tree[num].ps=tree[(num<<1)|1].ps;}
72 }
73
74 void build(int num,int l,int r)
75 {
76     if(l==r)
77     {
78         tree[num].l=tree[num].r=l;
79         tree[num].ps=l;
80         return;
81     }
82     int mid=(l+r)>>1;
83     build(num<<1,l,mid);
84     build((num<<1)|1,mid+1,r);
85     tree[num].l=l,tree[num].r=r;
86     tree[num].ps=tree[(num<<1)|1].ps;
87 }
88
89 int main()
90 {
91     long long ans=0;
92     int n,k;
93     n=read(),k=read();
94     for(int i=1;i<=n;i++)a[i]=read();
95     for(int i=1;i<n;i++)
96     {
97         int u,v;
98     u=read();v=read();
99     graph[u].push_back(v);
100     father[v]=u;
101     }
102
103     father[1]=0;
104
105     DFS(1);
106     build(1,1,n);
107
108     for(int i=1;i<=n;i++)
109         update(1,dfn[i],last[i],a[i]);
110
111     while(k--)
112     {
113     psh(1);
114     ans+=tree[1].num;
115     int u=rev[tree[1].ps];
116     while(u&&!vis[u])
117     {
118         vis[u]=1;
119         update(1,dfn[u],last[u],-a[u]);
120         u=father[u];
121     }
122     }
123     printf("%lld",ans);
124     return 0;
125 }


View Code
  (死于太久没打tag。。)

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: