清橙A1212:剪枝

题面

清橙

Sol

一种新的树上\(DP\)姿势
从左往右按链\(DP\)

做法:
维护两个栈\(S1\),\(S2\)
\(S1\)存当前的链
\(S2\)存分叉点以下要改的链
\(Dfs\),弄一个分叉点,之前的链经过它,并且另一条要转移到的链也经过它
那么每次在叶节点时就把\(S1\)最下面的一部分变成\(S2\)

转移
两种情况:
最大值在\(S1\)和在\(S2\)的情况
那么枚举\(S2\),\(S1\)中小于\(S2\)的枚举的值的点就可以转移,并维护\(S1\),\(S2\)的前缀最大值
再枚举\(S2\),利用前缀最大值,\(S1\)的大于等于\(S2\)的转移

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
# define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
using namespace std;
typedef long long ll;
const int _(1e5 + 5);

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

int n, val[_], f[_], ans = -2e9;
int fa[_], S1[_], S2[_], id[_], maxv[_];
vector <int> edge[_];

IL void Dfs(RG int u, RG int top){   //top是分叉点在S1中的位置
    if(!top) S1[++S1[0]] = u, id[u] = S1[0], f[u] = val[u]; //初始第一条链
    RG int l = edge[u].size();
    if(l){    //非叶子节点不做更新
        for(RG int i = 0; i < l; ++i){
            RG int v = edge[u][i];
            if(!i){   //最左边的直接加入S2
                if(top) S2[++S2[0]] = v;
                Dfs(v, top);
            }
            else S2[S2[0] = 1] = v, Dfs(v, id[u]); //新开一条链
        }
        return;
    }
    if(!top) return;
    RG int mx1 = val[S1[top]], maxf = ans, now = top, mx2 = mx1;
    for(RG int i = 1; i <= S2[0]; ++i){  //最大值在S2中的情况
        while(now < S1[0] && val[S1[now]] <= mx1){ //计算每个最大值的贡献
            mx2 = max(mx2, val[S1[now]]);
            maxf = max(maxf, f[S1[++now]]);
            maxv[S1[now]] = mx2;  //维护S1前缀最大值
        }
        f[S2[i]] = maxf - mx1;  //转移
        maxv[S2[i]] = mx1;  //维护S2前缀最大值
        mx1 = max(mx1, val[S2[i]]);   //下一个点
    }
    while(now < S1[0]){ //处理剩下的
        mx2 = max(mx2, val[S1[now]]);
        maxv[S1[++now]] = mx2;
    }
    maxf = ans, now = S1[0];
    for(RG int i = S2[0]; i; --i){ //最大值在S1中的情况
        while(now > top && maxv[S1[now]] >= maxv[S2[i]]){
            maxf = max(maxf, f[S1[now]] - maxv[S1[now]]);
            --now;
        }
        f[S2[i]] = max(f[S2[i]], maxf);
    }
    for(RG int i = 1; i <= S2[0]; ++i){ //更新到下一条链
        f[S2[i]] += val[S2[i]];
        S1[top + i] = S2[i];
        id[S2[i]] = top + i;
    }
    S1[0] = top + S2[0];
}

int main(RG int argc, RG char* argv[]){
    File("cut");
    n = Input(), Fill(f, -127);
    for(RG int i = 1, t; i <= n; ++i){
        val[i] = Input(), t = Input();
        for(RG int j = 1, tt; j <= t; ++j)
            tt = Input(), edge[i].push_back(tt);
    }
    Dfs(1, 0);
    for(RG int i = 1; i <= S1[0]; ++i) ans = max(ans, f[S1[i]]);
    printf("%d\n", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/cjoieryl/p/8476899.html

时间: 2024-10-29 14:32:32

清橙A1212:剪枝的相关文章

清橙A1363. 水位 - 清华大学2012年信息学优秀高中学子夏令营

问题描述 有一个正方形的地区,该地区特点鲜明:如果把它等分为N×N个小正方形格子的话,在每个格子内的任意地点的地表高度是相同的,并且是一个0到M之间的整数.正方形地区的外部被无限高的边界包围. 该地区可能会有积水.经过多年的观察,人们发现了几个关于积水的重要规律: 1. 每个格子要么完全没有积水,要么它内部的任意地点的水面高度都是相同的.并且水面高度一定大于地表高度. 2. 每个格子的水面高度在0~M之间,并且一定是整数. 3. 对于相邻(必须为边相邻)的两个格子,一定不会出现水自动从一个格子流

清橙A1206 小Z的袜子(莫队算法)

A1206. 小Z的袜子 时间限制:1.0s   内存限制:512.0MB 总提交次数:744   AC次数:210   平均分:44.44 将本题分享到: 查看未格式化的试题   提交   试题讨论 试题来源 2010中国国家集训队命题答辩 问题描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命-- 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是

[TS-A1505] [清橙2013中国国家集训队第二次作业] 树 [可持久化线段树,求树上路径第k大]

按Dfs序逐个插入点,建立可持久化线段树,每次查询即可,具体详见代码. 不知道为什么,代码慢的要死,, #include <iostream> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ctime> #include <vector> using

清橙A1484

http://www.tsinsen.com/ViewGProblem.page?gpid=A1484### 题解: 在线插入并不好做,我们将所有操作离线,变为删除操作. 每次询问的时候对于当前B串所在起始位置及其长度向上向下二分,然后查询区间内合法的当前A串内的匹配点即可. 用树状数组维护(不过我sb的写了线段树,后来才发现···). code: 1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #

【清橙A1084】【FFT】快速傅里叶变换

问题描述 离散傅立叶变换在信号处理中扮演者重要的角色.利用傅立叶变换,可以实现信号在时域和频域之间的转换. 对于一个给定的长度为n=2m (m为整数) 的复数序列X0, X1, …, Xn-1,离散傅立叶变换将得到另一个长度为n的复数序列Y0, Y1, …, Yn-1.其中 Yi=X0+X1wi+ X2w2i+ X3w3i+…+ Xn-1w(n-1)i 其中w=e2πI/n=cos(2π/n)+I sin(2π/n),称为旋转因子,其中I为虚数单位,I2= –1. 给定输入序列X,请输出傅立叶变

清橙A1339. JZPLCM(顾昱洲)

http://www.tsinsen.com/ViewGProblem.page?gpid=A1339 题解:https://blog.csdn.net/LOI_DQS/article/details/51251737 对着题解A掉了...然而并不知道为什么要这么转化问题... 复杂度nlog^2n级别吧 1 #include<cstdio> 2 #include<algorithm> 3 #include<map> 4 #include<cmath> 5

【刷题】清橙 A1339 JZPLCM(顾昱洲)

试题来源 2012中国国家集训队命题答辩 问题描述 给定一长度为n的正整数序列a,有q次询问,每次询问一段区间内所有数的lcm(即最小公倍数).由于答案可能很大,输出答案模1000000007. 输入格式 第一行,两个整数,n, q,分别表示数列长度和询问个数. 下面n行,每行一个整数,第i行的整数为ai. 下面q行,每行两个整数l, r,表示询问下标i在[l, r]范围内的ai的lcm. 输出格式 q行.对于每个询问,输出一行,表示对应的答案. 样例输入 3 3 123 234 345 1 2

[tsA1490][2013中国国家集训队第二次作业]osu![概率dp+线段树+矩阵乘法]

这样的题解只能舔题解了,,,qaq 清橙资料里有.. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cmath> 6 #include <ctime> 7 #include <algorithm> 8 9 using namespace std; 10 11 struct Mat

oj集

by http://www.cnblogs.com/yangqingli/p/4931360.html OnlineJudge大集合 什么是OJ Online Judge系统(简称OJ)是一个在线的判题系统.用户可以在线提交程序源代码,系统对源代码进行编译和执行,并通过预先设计的测试数据来检验程序源代码的正确性. 一个用户提交的程序在Online Judge系统下执行时将受到比较严格的限制,包括运行时间限制,内存使用限制和安全限制等.用户程序执行的结果将被Online Judge系统捕捉并保存,