@CSP模拟2019.10.16 - [email protected] 垃圾分类

目录

  • @[email protected]
  • @[email protected]
  • @accepted [email protected]
  • @[email protected]

@[email protected]

为了保护环境,p6pou建设了一个垃圾分类器。

垃圾分类器是一个树形结构,由 n 个垃圾桶和 n-1 条双向传送带组成。
垃圾处理器的编号为 1, 2, ..., n,每条传送带都可以花 1 秒钟将垃圾从一个垃圾桶输送到另一个垃圾桶。
垃圾投放点是编号为 r 的垃圾桶,垃圾总是投放在这里。

垃圾共有 n 种,编号也是 1, 2, ..., n。
编号为 i 的垃圾会被输送到编号为 i 的垃圾桶里面,垃圾总是自动沿着最短路线输送,到达编号为 i 的垃圾桶后需要 ai 秒才能被垃圾桶处理完成。

为了避免不同垃圾混在一起,p6pou将垃圾按照编号从小到大的顺序依次投入编号为 r 的垃圾桶,每投放一种垃圾之后,必须等到这种垃圾被输送到其他垃圾桶,或者被编号为 r 的垃圾桶处理完成,才能继续投放下一种垃圾。
传送带输送垃圾也一样,如果要将垃圾从编号为 x 的垃圾桶中的垃圾传输到编号为 y 的垃圾桶,如果此时编号为 y 的垃圾桶中有另一种垃圾,必须等到另一种垃圾被传输走或者被处理完成后才能传输。

现在p6pou想知道,开始投放垃圾到垃圾分类器处理完所有所有垃圾,总共需要花费多长时间。

输入格式
第一行两个整数 n, r,垃圾种类和垃圾桶数量都是 n,垃圾投放点是编号为 r 的垃圾桶。
第二行 n 个整数 a1, a2, ..., an,表示第 i 个垃圾桶处理第 i 种垃圾的时间。
接下来 n - 1 行每行两个数 x, y,表示有一条双向传送带连接编号为 x, y 的两个垃圾桶。

输出格式
输出一个整数,表示从开始投放垃圾到处理完所有垃圾的总时间。

输入输出样例1
样例输入
3 2
5 2 5
1 2
1 3
样例输出
14
样例说明
开始投放 2 秒后,1 号垃圾到达 1 号垃圾桶,2 号垃圾到达 2 号垃圾桶,3 号垃圾还没投放;
开始投放 4 秒后,2 号垃圾处理完成;
开始投放 5 秒后,3 号垃圾到达 2 号垃圾桶,此时 1 号垃圾桶仍在处理 1 号垃圾,所以 3 号垃圾无法传输, 在此等待;
开始投放 7 秒后,1 号垃圾处理完成;
开始投放 9 秒后,3 号垃圾到达 3 号垃圾桶;
开始投放 14 秒后,3 号垃圾处理完成。此时,所有垃圾都已经处理完。

输入输出样例2
样例输入
6 4
6 5 4 3 2 1
1 2
3 2
2 4
5 4
1 6
样例输出
18
样例说明
开始投放 9 秒后,1 号垃圾处理完;
开始投放 8 秒后,2 号垃圾处理完;
开始投放 14 秒后,3 号垃圾处理完;
开始投放 12 秒后,4 号垃圾处理完;
开始投放 16 秒后,5 号垃圾处理完;
开始投放 18 秒后,6 号垃圾处理完。

数据规模与约定
对于100%的数据, n <= 100000, 0 <= ai <= 10^9, 1 <= x, y <= n。

@[email protected]

首先转化一下问题,去除投放垃圾这一过程:
我们从 r 开始连出去 n 个点连成一条链,并把 1~n 号垃圾从前往后放置在这些点上面。即 n -> n-1 -> ... -> 1 -> r(前面的 1~n 是垃圾放置的对应结点)。
这样就只剩下垃圾在结点之间移动了。

考虑垃圾之间一般是不会互相影响的,垃圾 x 会堵塞垃圾 y,要么是因为垃圾 x 本身在处理,要么是垃圾 x 被前面某个垃圾间接堵塞了。

我们记标记 (x, t) 表示在时刻 t 之前无法通过 x,而从时刻 t 开始可以通过结点 x(通过包含到达的情况)。
注意这里的标记是一个下界,不一定时刻 t 一定就有垃圾通过结点 x。
那么标记的产生就会两种情况:某垃圾被处理了,某垃圾被间接堵塞了。

对于第 i 个垃圾,它到达的时间受它所在结点与目的地之间的路径上所有标记的影响。
它的终点为点 i,因为这些标记 (x, t) 对于 i 的影响为 t + dep[i] - dep[x]。
我们维护 max(t - dep[x]),就可以快速求出一个点到达目的地的时间。

然后考虑怎么维护标记:

先考虑间接堵塞,我们发现这个等价于所有标记上移到结点的父亲。
如果是在链上,这个操作可以用平衡树来维护(貌似也可以用线段树)。
如果是在树上,最常见的就是树链剖分转为序列问题。但是从重链顶端上移时,需要进行类区间拆分与区间合并的操作。于是就不得不用什么平衡树来做了。
貌似用 lct 要更自然一点。不过 splay 太难写了(

然后是自己被处理,会产生一个 (max(t - dep[x]) + dep[i] + a[i] +1, x) 的标记。平衡树上直接插入即可。这里的插入必须要在标记向上爬之后再插。

当然为了保证合法,我们还要加上标记 (1, 1)。
时间复杂度 O(nlog^2n)。

@accepted [email protected]

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF = (1LL<<60);
const int MAXN = 200000;
struct node{
    ull pri;
    ll tg, mx, val;
    int dep;
    node *ch[2];
}pl[MAXN + 5], *ncnt, *NIL;
typedef pair<node*, node*> Droot;
struct treap{
    treap() {
        NIL = ncnt = &pl[0];
        NIL->mx = -INF;
        NIL->ch[0] = NIL->ch[1] = NIL;
    }
    ull get_rand() {
        ull p = rand(), q = (p << 16) | rand();
        ull u = rand(), v = (u << 16) | rand();
        return (q << 32) | v;
    }
    node *newnode(ll x, int d) {
        node *p = (++ncnt);
        p->dep = d, p->mx = p->val = x;
        p->pri = get_rand(), p->tg = 0;
        p->ch[0] = p->ch[1] = NIL;
        return p;
    }
    void maintain(node *x, ll k) {
        if( x == NIL ) return ;
        x->tg += k, x->mx += k, x->val += k, x->dep -= k;
    }
    void pushup(node *x) {
        x->mx = max(max(x->ch[0]->mx, x->ch[1]->mx), x->val);
    }
    void pushdown(node *x) {
        if( x->tg ) {
            maintain(x->ch[0], x->tg);
            maintain(x->ch[1], x->tg);
            x->tg = 0;
        }
    }
    node *merge(node *x, node *y) {
        if( x == NIL ) return y;
        if( y == NIL ) return x;
        pushdown(x), pushdown(y);
        if( x->pri < y->pri ) {
            x->ch[1] = merge(x->ch[1], y);
            pushup(x); return x;
        }
        else {
            y->ch[0] = merge(x, y->ch[0]);
            pushup(y); return y;
        }
    }
    Droot split(node *x, int k) {
        if( x == NIL ) return make_pair(NIL, NIL);
        pushdown(x);
        if( k < x->dep ) {
            Droot p = split(x->ch[0], k);
            x->ch[0] = p.second; pushup(x);
            return make_pair(p.first, x);
        }
        else {
            Droot p = split(x->ch[1], k);
            x->ch[1] = p.first; pushup(x);
            return make_pair(x, p.second);
        }
    }
    node *insert(node *x, node *y) {
        Droot p = split(x, y->dep);
        return merge(p.first, merge(y, p.second));
    }
}T;
struct edge{
    int to; edge *nxt;
}edges[2*MAXN + 5], *adj[MAXN + 5], *ecnt=&edges[0];
void addedge(int u, int v) {
    edge *p = (++ecnt);
    p->to = v, p->nxt = adj[u], adj[u] = p;
    p = (++ecnt);
    p->to = u, p->nxt = adj[v], adj[v] = p;
}
int hvy[MAXN + 5], siz[MAXN + 5], dep[MAXN + 5], fa[MAXN + 5];
void dfs1(int x, int f) {
    siz[x] = 1, dep[x] = dep[f] + 1, fa[x] = f, hvy[x] = 0;
    for(edge *p=adj[x];p;p=p->nxt) {
        if( p->to == f ) continue;
        dfs1(p->to, x);
        siz[x] += siz[p->to];
        if( siz[hvy[x]] < siz[p->to] )
            hvy[x] = p->to;
    }
}
node *rt[MAXN + 5];
int top[MAXN + 5], tid[MAXN + 5], dfn[MAXN + 5], dcnt = 0;
void dfs2(int x, int tp) {
    rt[x] = NIL;
    top[x] = tp, tid[x] = (++dcnt), dfn[dcnt] = x;
    if( !hvy[x] ) return ;
    dfs2(hvy[x], tp);
    for(edge *p=adj[x];p;p=p->nxt)
        if( p->to != fa[x] && p->to != hvy[x] )
            dfs2(p->to, p->to);
}
void insert(int x, ll k) {
    node *p = T.newnode(k - dep[x], dep[x]);
    rt[top[x]] = T.insert(rt[top[x]], p);
}
ll query(int x) {
    ll ret = -INF;
    while( x ) {
        Droot p = T.split(rt[top[x]], dep[x]);
        ret = max(ret, p.first->mx);
        rt[top[x]] = T.merge(p.first, p.second);
        x = fa[top[x]];
    }
    return ret;
}
void update(int x) {
    node *y = NIL;
    while( x ) {
        Droot p = T.split(rt[top[x]], dep[x]);
        T.maintain(p.first, 1);
        rt[top[x]] = T.merge(p.first, p.second);
        p = T.split(rt[top[x]], dep[top[x]] - 1);
        rt[top[x]] = T.insert(p.second, y), y = p.first;
        x = fa[top[x]];
    }
}
int a[MAXN + 5], n, r;
int main() {
    freopen("garbage.in", "r", stdin);
    freopen("garbage.out", "w", stdout);
    srand(0307); scanf("%d%d", &n, &r);
    for(int i=1;i<=n;i++)
        scanf("%d", &a[i]);
    for(int i=1;i<n;i++) {
        int u, v; scanf("%d%d", &u, &v);
        addedge(u, v);
    }
    addedge(r, n + 1);
    for(int i=2;i<=n;i++) addedge(n + i - 1, n + i);
    dfs1(2*n, 0), dfs2(2*n, 2*n), insert(r, 1);
    ll ans = 0;
    for(int i=1;i<=n;i++) {
        ll tmp = dep[i] + query(i) + a[i];
        update(i), insert(i, tmp + 1);
        ans = max(ans, tmp);
    }
    printf("%lld\n", ans);
}

@[email protected]

出题人在嘲讽选手是垃圾

话说树链剖分套平衡树是否超出了 CSP 的考纲范围内。
(也不一定,毕竟去年连 ddp 都考)

原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/11697789.html

时间: 2024-10-08 08:54:52

@CSP模拟2019.10.16 - [email protected] 垃圾分类的相关文章

2019.10.16&amp;17小结

话说也蛮久没写小结了,主要这两次考试失分严重,还是总结下吧. 10.16 T1 小奇挖矿2 100/0 [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿石交易市场,以便为飞船升级无限非概率引擎. [问题描述] 现在有m+1个星球,从左到右标号为0到m,小奇最初在0号星球. 有n处矿体,第i处矿体有ai单位原矿,在第bi个星球上. 由于飞船使用的是老式的跳跃引擎,每次它只能从第x号星球移动到第x+4号星球或x+7号星球.每到一个星球,小奇会采走该星球上所有的

python 2019.10.16

学了if语句 if 条件: 结果 if 条件: 结果 elif 条件: 结果 else: 结果 while循环 while 循环条件: 循环体 循环终止 1.改变循环条件终止 2.break 终止循环 3.continue 跳过本次循环继续下次循环 while 循环条件: 循环体 else:#循环结束后运行else 占位符 %$:表示字符串 $d表示数字 例: name = input("请输入你的名字") age = int(input("请输入你的年龄")) h

2019/10/16 无向图最小环算法研究

例题:POJ1734http://poj.org/problem?id=1734 考虑Floyd算法的过程,在外层循环k刚开始的时候,d[i,j]保存着“经过编号不超过k-1的节点”从i到j的最短路 于是 min{d[i,j]+a[i][k]+a[k][j]}  1<=i<j<k; 即为所求的最小环 #include<vector>#include<cstdio>#include<cstring>using namespace std;vector &

2019.10.16 每天问自己 三遍 或者更多:我收获了什么?我收获了什么?我收获了什么???

今天接收到的一个非常重要的挂反思就是每天都这么问问自己:我今天收获了什么? 因为今天看了这篇文章https://www.cnblogs.com/xiyuanMore/p/11673560.html 学习上,概率论听的还不错,但是没有做完题: 下午忙忙忙 主要是前期没统一 白做无用功 晚上效率不是很高.走神是个问题. 当然了 今天最大的收获就是跟洒洒好好交流 原文地址:https://www.cnblogs.com/juzijuziju/p/11689532.html

如何去掉[email&#160;protected]中的@符号Linux文件扩展信息

如何去掉[email protected]中的@符号Linux文件扩展信息ls -lart [email protected] 10 rlanffy staff 340B 3 6 2015 [email protected] 1 rlanffy staff 630B 6 10 17:22 [email protected] 1 rlanffy staff 4.8K 8 12 14:17 [email protected] 3 rlanffy staff 102B 8 14 12:10 [emai

@bzoj - [email&#160;protected] [POI2015] Odwiedziny

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 给定一棵 n 个点的树,树上每条边的长度都为 1 ,第 i 个点的权值为 a[i]. Byteasar 会按照某个 1 到 n 的全排列 b 走 n-1 次,第 i 次他会从 b[i] 点走到 b[i+1] 点,并且这一次的步伐大小为 c[i]. 对于一次行走,假设起点为 x,终点为

让Windows Server 2008 + IIS 7+ ASP.NET 支持10万并发请求 The [email&#160;protected] setting is being exceeded.

今天下午17点左右,博客园博客站点出现这样的错误信息: Error Summary: HTTP Error 503.2 - Service UnavailableThe [email protected] setting is being exceeded. Detailed Error Information: Module IIS Web Core Notification BeginRequest Handler StaticFile Error Code 0x00000000 由于之前使

@雅礼集训01/10 - [email&#160;protected] matrix

目录 @[email protected] @[email protected] @[email protected] @[email protected] @[email protected] 给定一个矩阵.求它的所有子矩阵中本质不同的行的个数之和. input 第一行,两个正整数 n, m. 第二行,n * m 个正整数,第 i 个数表示 A[i/m][i mod m]. 保证 n * m <= 10^5, 1 <= A[i][j] <= 10^9 output 输出一个非负整数表示

Shell特殊变量:Shell $0, $#, $*, [email&#160;protected], $?, $$和命令行参数

变量名只能包含数字.字母和下划线,因为某些包含其他字符的变量有特殊含义,这样的变量被称为特殊变量. 例如,$ 表示当前Shell进程的ID,即pid,看下面的代码: $echo $$ 运行结果 29949 特殊变量列表 变量 含义 $0 当前脚本的文件名 $n 传递给脚本或函数的参数.n 是一个数字,表示第几个参数.例如,第一个参数是$1,第二个参数是$2. $# 传递给脚本或函数的参数个数. $* 传递给脚本或函数的所有参数. [email protected] 传递给脚本或函数的所有参数.被