Bzoj2809 APIO2012 派遣 主席树经典题
2014-04-21 18:27
197 查看
这个题。。。。
真的是整死我了。。
首先看哪个领导者
这个是需要枚举的,很简单不解释了
下面分析如果固定一个领导者的求解过程
首先我们注意到ans是人数乘以领导值
而领导值通过枚举已经固定了
那么就是求人数的问题了
那么可以肯定的是每个人对答案的贡献都是一样的,但是他们的薪水不一样
所以有点智商的人都会选哪个薪水小的
所以就是枚举以后的区间k小了
splay显然是可以的
我为了加深对主席树的理解专门用了主席树
如果不会主席树可以看这里
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define MAX 100009
#define Max 3800009
#define inf 0x7fffffff
#define ll long long
#define rep(i, j, k) for(int i = j; i <= k; i++)
using namespace std;
int to[MAX * 2], head[MAX],next[MAX * 2], first[MAX], last[MAX];
int DfsColck = 0, dfn[MAX * 2], root, cnt = 0;
int tree[MAX], child[Max][2], size[Max], s = 0, tot = 0;
int n, rank[MAX], t[MAX * 2];
ll sum[Max], m, ans = -inf;
int a[MAX][2];
struct wbysr
{
ll v;
int t;
}b[MAX];
inline void add (int x, int y)
{
to[++tot] = y;
next[tot] = head[x];
head[x] = tot;
}
bool cmp (wbysr a1, wbysr a2)
{
return a1.v < a2.v;
}
void dfs (int x)
{
dfn[first[x] = ++DfsColck] = x;
for (int i = head[x]; i; i = next[i])
dfs (to[i]);
dfn[last[x] = ++DfsColck] = x;
}
inline int build (int l, int r)
{
int Root = ++cnt;
tree[Root] = 0;
if(l != r)
{
int mid = (l + r) >> 1;
child[Root][0] = build (l, mid);
child[Root][1] = build (mid + 1, r);
}
return Root;
}
int update (int l, int r, int Root, int pos, ll value)
{
int New = ++cnt;
size[New] = size[Root] + 1;
sum[New] = sum[Root] + value;
if (l == r)
return New;
int mid = (l + r) >> 1;
if (pos <= mid)
child[New][1] = child[Root][1], child[New][0] = update (l, mid, child[Root][0], pos, value);
else
child[New][0] = child[Root][0], child[New][1] = update (mid+1, r, child[Root][1], pos, value);
return New;
}
inline void debug ()
{
rep (i, 0, DfsColck)
printf ("%d %d\n", i, t[i]);
}
int main()
{
scanf ("%d%lld", &n, &m);
m *= 2;
rep (i, 1, n)
{
int x;
scanf ("%d%lld%lld", &x, &a[i][0], &a[i][1]);
if (x)
add (x, i);
else
root = i;
b[i].v = a[i][0];
b[i].t = i;
}
b[n + 1].v = -inf, b[n + 1].t = 0;
b[s = n + 2].v = inf, b[s].t = 0;
sort (b + 1, b + 1 + s, cmp);
rep (i, 1, s)
rank[ b[i].t ] = i;
dfs ( root );
t[0] = 0;
rep (i, 1, DfsColck)
t[i] = update (1, s, t[i - 1], rank[ dfn[i] ], a[ dfn[i] ][0]);
//debug ();
rep (i, 1, n)
{
ll num = 0, rec = m;
int t0 = t[first[i] - 1], t1 = t[last[i]];
int l = 1, r = s;
while (l < r)
{
ll now = sum[child[t1][0]] - sum[child[t0][0]];
int mid = (l + r) >> 1;
if (now <= rec)
{
rec -= now;
num += size[child[t1][0]] - size[child[t0][0]];
t0 = child[t0][1];
t1 = child[t1][1];
l = mid + 1;
}
else
{
t0 = child[t0][0];
t1 = child[t1][0];
r = mid;
}
}
ans = max (ans, (num / 2) * a[i][1]);
}
printf ("%lld\n", ans);
return 0;
}
真的是整死我了。。
首先看哪个领导者
这个是需要枚举的,很简单不解释了
下面分析如果固定一个领导者的求解过程
首先我们注意到ans是人数乘以领导值
而领导值通过枚举已经固定了
那么就是求人数的问题了
那么可以肯定的是每个人对答案的贡献都是一样的,但是他们的薪水不一样
所以有点智商的人都会选哪个薪水小的
所以就是枚举以后的区间k小了
splay显然是可以的
我为了加深对主席树的理解专门用了主席树
如果不会主席树可以看这里
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define MAX 100009
#define Max 3800009
#define inf 0x7fffffff
#define ll long long
#define rep(i, j, k) for(int i = j; i <= k; i++)
using namespace std;
int to[MAX * 2], head[MAX],next[MAX * 2], first[MAX], last[MAX];
int DfsColck = 0, dfn[MAX * 2], root, cnt = 0;
int tree[MAX], child[Max][2], size[Max], s = 0, tot = 0;
int n, rank[MAX], t[MAX * 2];
ll sum[Max], m, ans = -inf;
int a[MAX][2];
struct wbysr
{
ll v;
int t;
}b[MAX];
inline void add (int x, int y)
{
to[++tot] = y;
next[tot] = head[x];
head[x] = tot;
}
bool cmp (wbysr a1, wbysr a2)
{
return a1.v < a2.v;
}
void dfs (int x)
{
dfn[first[x] = ++DfsColck] = x;
for (int i = head[x]; i; i = next[i])
dfs (to[i]);
dfn[last[x] = ++DfsColck] = x;
}
inline int build (int l, int r)
{
int Root = ++cnt;
tree[Root] = 0;
if(l != r)
{
int mid = (l + r) >> 1;
child[Root][0] = build (l, mid);
child[Root][1] = build (mid + 1, r);
}
return Root;
}
int update (int l, int r, int Root, int pos, ll value)
{
int New = ++cnt;
size[New] = size[Root] + 1;
sum[New] = sum[Root] + value;
if (l == r)
return New;
int mid = (l + r) >> 1;
if (pos <= mid)
child[New][1] = child[Root][1], child[New][0] = update (l, mid, child[Root][0], pos, value);
else
child[New][0] = child[Root][0], child[New][1] = update (mid+1, r, child[Root][1], pos, value);
return New;
}
inline void debug ()
{
rep (i, 0, DfsColck)
printf ("%d %d\n", i, t[i]);
}
int main()
{
scanf ("%d%lld", &n, &m);
m *= 2;
rep (i, 1, n)
{
int x;
scanf ("%d%lld%lld", &x, &a[i][0], &a[i][1]);
if (x)
add (x, i);
else
root = i;
b[i].v = a[i][0];
b[i].t = i;
}
b[n + 1].v = -inf, b[n + 1].t = 0;
b[s = n + 2].v = inf, b[s].t = 0;
sort (b + 1, b + 1 + s, cmp);
rep (i, 1, s)
rank[ b[i].t ] = i;
dfs ( root );
t[0] = 0;
rep (i, 1, DfsColck)
t[i] = update (1, s, t[i - 1], rank[ dfn[i] ], a[ dfn[i] ][0]);
//debug ();
rep (i, 1, n)
{
ll num = 0, rec = m;
int t0 = t[first[i] - 1], t1 = t[last[i]];
int l = 1, r = s;
while (l < r)
{
ll now = sum[child[t1][0]] - sum[child[t0][0]];
int mid = (l + r) >> 1;
if (now <= rec)
{
rec -= now;
num += size[child[t1][0]] - size[child[t0][0]];
t0 = child[t0][1];
t1 = child[t1][1];
l = mid + 1;
}
else
{
t0 = child[t0][0];
t1 = child[t1][0];
r = mid;
}
}
ans = max (ans, (num / 2) * a[i][1]);
}
printf ("%lld\n", ans);
return 0;
}
相关文章推荐
- [APIO2012]派遣 解题报告
- [APIO2012] 派遣 dispatching
- [Apio2012]dispatching 主席树做法
- 数据结构,可并堆(左偏树):COGS [APIO2012] 派遣
- 派遣 APIO-2012
- 【APIO 2012】派遣(弱数据版)
- [APIO2012] 派遣
- P1552 [APIO2012]派遣
- 【洛谷P1552】【APIO2012】派遣
- [APIO2012]派遣 (平衡树启发式合并)
- [BZOJ]2809: [Apio2012]dispatching 主席树(线段树合并)
- bzoj2809 apio2012 派遣
- 【BZOJ】【2809】【APIO2012】派遣dispatching
- 【BZOJ2809】【APIO2012】派遣
- [APIO 2012]派遣
- 省选专练APIO2012派遣
- [Apio2012][Treap]派遣
- 【bzoj2809】[Apio2012]dispatching 主席树+dfs序
- [BZOJ2809][Apio2012]dispatching(dfs序+主席树)
- [洛谷P1552] [APIO2012]派遣