传送门

考场上坚持认为树上背包可以有70pts,于是爆零了

首先我以为是树上背包的部分分其实是树形DP

然后极其魔鬼的正解:

首先我们令 \(dp[i][j]\) 为以i为根的子树覆盖次数至多为j时的方案数(我考场上那个没搞出来的dp定义是恰好

然后45pts的 \(n^2\) 就可以做了,考虑如何优化

  • 有些树形DP(只包含子树合并和形似 \(dp[i][j] = max(dp[i][j], dp[i][j-1]+a[i]\) 的转移),会有个性质:其差分值单调不增,然后这个差分表可以直接用个堆或者multiset一个log维护

接下来考虑如何维护每个点的贡献,也即 \(dp[i][j-1]+val[i]\)

举个来自战神的例子

3 5 6 插入2 变为 3 5 7 8 对应差分表由2 1变为2 2 1

所以这里第二个式子的贡献就等价于把这个 \(val[i]\) 直接扔堆里,然后就极好维护了

启发式合并即可

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 300010
#define ll long long
#define pb push_back
#define reg register int
//#define int long long char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
} int n, m;
int l[N], r[N], uni[N<<1], usize;
ll a[N]; namespace force{
int cnt[N]; ll ans;
void solve() {
int lim=1<<m;
for (reg k=1; k<=m; ++k) {
ans=0;
for (reg s=1; s<lim; ++s) {
ll sum=0;
memset(cnt+1, 0, sizeof(int)*usize);
//memset(cnt, 0, sizeof(cnt));
for (reg i=0; i<m; ++i) if (s&(1<<i)) {
sum+=a[i+1];
for (reg j=l[i+1]; j<max(l[i+1]+1, r[i+1]); ++j)
if (++cnt[j]>k) goto jump;
}
ans=max(ans, sum);
jump: ;
}
printf("%lld ", ans);
}
printf("\n");
exit(0);
}
} namespace task1{
int head[N], size, top, dp[5010][5010];
struct edge{int to, next;}e[N<<1];
inline void add(int s, int t) {edge* k=&e[++size]; k->to=t; k->next=head[s]; head[s]=size;}
struct seg{int l, r, a; inline void build(int l_, int r_, int a_){l=l_; r=r_; a=a_;}}s[N], sta[N];
inline bool operator < (seg a, seg b) {return a.l==b.l?a.r>b.r:a.l<b.l;};
vector<int> e2[N], val[N];
int dfs(int u) {
int p=1;
for (int i=0; i<(int)(val[u].size()); ++i)
for (int j=m; j; --j)
dp[u][j] = max(dp[u][j], dp[u][j-1]+val[u][i]);
for (int i=head[u],v,siz; i; i=e[i].next) {
v = e[i].to;
siz=dfs(v);
for (int j=m; ~j; --j) {
for (int h=1; j+h<=m; ++h) {
dp[u][j+h] = max(dp[u][j+h], dp[u][j]+dp[v][h]);
}
}
p+=siz;
}
return p;
}
void solve() {
for (int i=1; i<=m; ++i) s[i].build(l[i], r[i], a[i]);
sort(s+1, s+m+1);
for (int i=1; i<=m; ++i) {
while (top && sta[top].r<=s[i].l) --top;
if (top) e2[sta[top].l].pb(s[i].l);
else e2[0].pb(s[i].l);
sta[++top]=s[i];
val[max(s[i].l, s[i].r-1)].pb(s[i].a);
}
for (int i=0,newsize; i<=usize; ++i) {
newsize=unique(e2[i].begin(), e2[i].end())-e2[i].begin();
e2[i].resize(newsize);
for (int j=0; j<(int)(e2[i].size()); ++j) if (i!=e2[i][j]) add(i, e2[i][j]), cout<<"add "<<i<<' '<<e2[i][j]<<endl;
}
dfs(0);
for (int i=1; i<=m; ++i) cout<<dp[3][i]<<' '; cout<<endl;
for (int i=1,sum; i<=m; ++i) {
sum=0;
for (int j=head[0]; j; j=e[j].next)
sum+=dp[e[j].to][i];
printf("%d ", sum);
}
printf("\n");
exit(0);
}
} namespace task2{
int head[N], size, top, tot; ll dp[5010][5010];
struct edge{int to, next;}e[N<<1];
inline void add(int s, int t) {edge* k=&e[++size]; k->to=t; k->next=head[s]; head[s]=size;}
struct seg{int l, r, rk; ll a; inline void build(int l_, int r_, ll a_){l=l_; r=r_; a=a_;}}s[N], sta[N];
inline bool operator < (seg a, seg b) {return a.l==b.l?a.r>b.r:a.l<b.l;};
inline bool cmp(int a, int b) {return a>b;}
vector<ll> val[N];
int dfs(int u) {
int p=1;
for (int i=head[u],v,siz; i; i=e[i].next) {
v = e[i].to;
siz=dfs(v);
for (int j=1; j<=m; ++j) dp[u][j]+=dp[v][j];
p+=siz;
}
//if (u==3) {cout<<"dp[3]: "; for (int i=1; i<=m; ++i) cout<<dp[u][i]<<' '; cout<<endl;}
for (int i=0; i<(int)(val[u].size()); ++i)
for (int j=m; j>i; --j)
dp[u][j] = max(dp[u][j], dp[u][j-1]+val[u][i]);
//if (u==3) {cout<<"dp[3]: "; for (int i=1; i<=m; ++i) cout<<dp[u][i]<<' '; cout<<endl;}
return p;
}
void solve() {
for (int i=1; i<=m; ++i) s[i].build(l[i], r[i], a[i]); //, cout<<r[i]<<' '; cout<<endl;
s[m+1].build(1, usize+1, 0);
sort(s+1, s+m+2);
for (int i=1; i<=m+1; ++i) {
while (top && sta[top].r<=s[i].l && sta[top].l!=s[i].l) --top;
if (top && sta[top].l==s[i].l && sta[top].r==s[i].r) {
val[sta[top].rk].pb(s[i].a);
continue;
}
if (top) add(sta[top].rk, s[i].rk=++tot);
else s[i].rk=++tot;
sta[++top]=s[i];
val[tot].pb(s[i].a);
}
//cout<<"tot: "<<tot<<endl;
//cout<<"size: "<<size<<endl;
for (int i=1; i<=tot; ++i) sort(val[i].begin(), val[i].end(), cmp);
dfs(1);
//cout<<"dp: "; for (int i=1; i<=m; ++i) cout<<dp[2][i]<<' '; cout<<endl;
ll sum;
for (int i=1; i<=m; ++i) {
sum=0;
for (int j=head[1]; j; j=e[j].next)
sum+=dp[e[j].to][i];
printf("%lld ", sum);
}
printf("\n");
exit(0);
}
} namespace task{
int head[N], size, top, tot, siz[N], msiz[N], mson[N], stop; ll st[N];
priority_queue<ll> dp[N];
struct edge{int to, next;}e[N<<1];
inline void add(int s, int t) {edge* k=&e[++size]; k->to=t; k->next=head[s]; head[s]=size;}
struct seg{int l, r, rk; ll a; inline void build(int l_, int r_, ll a_){l=l_; r=r_; a=a_;}}s[N], sta[N];
inline bool operator < (seg a, seg b) {return a.l==b.l?a.r>b.r:a.l<b.l;};
inline bool cmp(int a, int b) {return a>b;}
vector<ll> val[N];
void dfs1(int u) {
siz[u]=1;
for (int i=head[u],v; i; i=e[i].next) {
v = e[i].to;
dfs1(v);
siz[u]+=siz[v];
if (siz[v]>msiz[u]) msiz[u]=siz[v], mson[u]=v;
}
}
void dfs2(int u) {
if (!mson[u]) {for (auto it:val[u]) dp[u].push(it); return;}
bool empty=0; stop=0;
for (int i=head[u]; i; i=e[i].next) dfs2(e[i].to);
swap(dp[u], dp[mson[u]]);
while (!empty) {
empty=1; ++stop;
for (int i=head[u],v; i; i=e[i].next) {
v = e[i].to;
if (v==mson[u]) continue;
if (!dp[v].empty()) {
empty=0;
st[stop]+=dp[v].top(); dp[v].pop();
}
}
if (!empty) {if (!dp[u].empty()) st[stop]+=dp[u].top(), dp[u].pop();}
else --stop;
}
for (int i=1; i<=stop; ++i) dp[u].push(st[i]), st[i]=0;
for (auto it:val[u]) dp[u].push(it); //, cout<<1<<endl;
}
void solve() {
for (int i=1; i<=m; ++i) s[i].build(l[i], r[i], a[i]); //, cout<<r[i]<<' '; cout<<endl;
s[m+1].build(1, usize+1, 0);
sort(s+1, s+m+2);
for (int i=1; i<=m+1; ++i) {
while (top && sta[top].r<=s[i].l && sta[top].l!=s[i].l) --top;
if (top && sta[top].l==s[i].l && sta[top].r==s[i].r) {
val[sta[top].rk].pb(s[i].a);
continue;
}
if (top) add(sta[top].rk, s[i].rk=++tot);
else s[i].rk=++tot;
sta[++top]=s[i];
val[tot].pb(s[i].a);
}
//cout<<"tot: "<<tot<<endl;
//cout<<"size: "<<size<<endl;
dfs1(1); dfs2(1);
//cout<<"dp: "; for (int i=1; i<=m; ++i) cout<<dp[2][i]<<' '; cout<<endl;
ll sum=0;
for (int i=1; i<=m; ++i) {
if (!dp[1].empty()) sum+=dp[1].top(), dp[1].pop();
printf("%lld ", sum);
}
printf("\n");
exit(0);
}
} signed main()
{
n=read(); m=read();
for (int i=1; i<=m; ++i) {
l[i]=read(); r[i]=read(); a[i]=read();
uni[++usize]=l[i]; uni[++usize]=r[i];
}
sort(uni+1, uni+usize+1);
usize=unique(uni+1, uni+usize+1)-uni-1;
//cout<<"usize: "<<usize<<endl;
for (int i=1; i<=m; ++i) {
//cout<<"old: "<<l[i]<<' '<<r[i]<<endl;
l[i]=lower_bound(uni+1, uni+usize+1, l[i])-uni;
r[i]=lower_bound(uni+1, uni+usize+1, r[i])-uni;
//cout<<"new: "<<l[i]<<' '<<r[i]<<endl;
}
//force::solve();
//task1::solve();
task::solve(); return 0;
}

题解 Cover的更多相关文章

  1. 题解 P3717 【[AHOI2017初中组]cover】

    题目链接 本题的大致思路就是搜索. 将矩阵初始化成false.先把灯塔标记.在搜一遍灯塔能照到的点并标记.最后搜一遍找被灯塔标记的个数. 详细解释见题解. 题解走起. #include<bits ...

  2. Gym 100431E Word Cover 题解:KMP上跑dp

    题意: 给你一个串,问你他的每个前缀的最小重复单元,其中单元是可以重叠的,最后按顺序输出即可.比如样例中abaabaa的最小重复单元为abaa,所以相应输出为4. 样例: input : abaaba ...

  3. 【题解】Luogu SP1435 PT07X - Vertex Cover

    原题传送门 求树的最小点覆盖,就是一个树形dp 类似于没有上司的舞会 dp的状态为\(f[i][0/1]\),表示i节点是否选择 边界是\(f[x][0]=0\),\(f[x][1]=1\) 转移方程 ...

  4. SCU 4439 Vertex Cover(二分图最小覆盖点)题解

    题意:每一条边至少有一个端点要涂颜色,问最少涂几个点 思路:最小顶点覆盖:用最少的点,让每条边都至少和其中一个点关联,显然是道裸最小顶点覆盖题: 参考:二分图 代码: #include<iost ...

  5. CF1175E Minimal Segment Cover 题解

    题意:给出\(n\)个形如\([l,r]\)的线段.\(m\)次询问,每次询问区间\([x,y]\),问至少选出几条线段,使得区间\([x,y]\)的任何一个部位都被至少一条线段覆盖. 首先有一个显然 ...

  6. URAL 2038 Minimum Vertex Cover

    2038. Minimum Vertex Cover Time limit: 1.0 secondMemory limit: 64 MB A vertex cover of a graph is a ...

  7. 题解-AtCoder Code-Festival2017 Final-J Tree MST

    Problem \(\mathrm{Code~Festival~2017~Final~J}\) 题意概要:一棵 \(n\) 个节点有点权边权的树.构建一张完全图,对于任意一对点 \((x,y)\),连 ...

  8. 【Codeforces Round】 #431 (Div. 2) 题解

    Codeforces Round #431 (Div. 2)  A. Odds and Ends time limit per test 1 second memory limit per test ...

  9. leetcode & lintcode 题解

    刷题备忘录,for bug-free 招行面试题--求无序数组最长连续序列的长度,这里连续指的是值连续--间隔为1,并不是数值的位置连续 问题: 给出一个未排序的整数数组,找出最长的连续元素序列的长度 ...

随机推荐

  1. WAF集成:Acunetix和FortiWeb

    Acunetix API使您有机会自动化任务以提高效率,尤其是在您可以加速与工作流其他组件的集成功能时.在此示例中,我们将在上一篇文章的基础上,向您展示如何在Bash脚本中使用Acunetix API ...

  2. WPF项目升级sqlite-net-pcl时遇到Library e_sqlite3 not found的问题解决办法记录

    项目中为了方便的存储本地数据,使用了SQLite数据库作为数据存储,再设计时DB.models引用了sqlite-net-pcl,那么项目再升级sqlite-net-pc 1.7.335l版本后后,遇 ...

  3. ESP32-性能监控笔记

    基于ESP-IDF4.1 1 #include <stdio.h> 2 #include <string.h> 3 #include <unistd.h> 4 #i ...

  4. Redis学习——数据结构下

    4.集合(集合(set)类型也是用来保存多个的字符串元素,但和列表类型不一样的是,集合中不允许有重复元素,并且集合中的元素是无序的,不能通过索引下标获取元素.) 1.命令 .集合内操作 1.添加元素 ...

  5. Easyui动态添加控件无法渲染 $.parser.parse()无效

    本文链接:https://blog.csdn.net/huangbaokang/article/details/78367553动态添加easyui控件<input class="ea ...

  6. POJ3179 Corral the Cows题解

    我就是个垃圾--一道水题能写这么长时间-- 首先看到题就想到了二维前缀和+二分边长,但地图边长10000,得离散化. 于是这个离散化就把我搞疯了,淦. 这反映出现在基础知识还是不牢固,相当不牢固. 复 ...

  7. [考试总结]noip模拟12

    菜 今天总体来说 菜爆了,打了 \(3\) 个暴力,没有一个是正解,并且每一个分数都低得要命... 主要还是太菜了... 第一题开题发现和昨天 \(T3\) 一样,然而因为还没学可持久化数据结构就咕掉 ...

  8. java学习笔记之OOP(二)

    java学习笔记二.面向对象[OOP]Object Oriented Programming 一.三大特性: 1.封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用 ...

  9. Win10强制程序高DPI缩放设置

    起因 工作原因,需要在win10上安装数个古老vc版本(vc6,vc2008,vc2010),但是显示器是2K的,DPI缩放有问题 尝试 VC6比较好解决:右键,属性,兼容性,更改高DPI设置,勾选替 ...

  10. Python - 对象赋值、浅拷贝、深拷贝的区别

    前言 Python 中不存在值传递,一切传递的都是对象的引用,也可以认为是传址 这里会讲三个概念:对象赋值.浅拷贝.深拷贝 名词解释 变量:存储对象的引用 对象:会被分配一块内存,存储实际的数据,比如 ...