【CF 678F】Lena and Queries
Time Limit: 2000 ms Memory Limit: 512 MB
Description
初始有一个空集合
n个操作
有三种操作,如下:
1 a b 表示向集合中插入二元组(a,b)
2 i 表示删除第i次操作时所插入的二元组
3 q 表示询问当前集合的二元组中,$(a*q+b)$最大是多少
Input
第一行一个整数$n$,表示操作个数
接下来$n$行,每行表示一个操作,格式见上
Output
对于每个询问输出一行表示最大值
如果询问时集合为空,输出 EMPTY SET
Sample Input
7
3 1
1 2 3
3 1
1 -1 100
3 1
2 4
3 1
Sample Output
EMPTY SET
5
99
5
Hint
对于操作$2~i$,数据保证第$i$次操作的类型为$1$,且之前未被删除,且不会删除仍未进行的操作
对于$10\%$的数据,$1\le n\le 5000$
对于$30\%$的数据,$1\le n\le 50000$
对于$100\%$的数据,$1\le n\le 3*10^5,~~-10^9\le a,b,q\le 10^9$
题解
先考虑点集不变的情况:
我们设$x=q*a+b$,那么目标就是在集合中找到最大的$k$。
移一下项:$b=-q*a+x$,现在的目标变为,对于每一个$(a,b)$的点对画一条斜率为$q$的直线,最大化截距。
就像平移一样,如下图所示,黑点代表一个$(a,b)$,橙点代表其所对应的截距,也就是$(a*q+b)$:

我们要最大化截距,而直线都是平行地平移来平移去,直线斜率的正负已经不重要了,取上凸壳的点才有可能是最优解:

注意并不是取上凸壳最高的点就是最优解,拿上图的最右上角的黑点举例,在另一个例子中,反倒是经过另一个点的直线截距最大:

但是不管怎样,如果从左到右看上凸壳的点,截距的变化是一个单峰函数。
那么我们就可以在上凸壳进行三分(以每一个点的截距为关键值)。
点集的变化?
建立一棵以时间为下标的线段树,每一个线段树节点都有一个上凸壳,包含在这个节点代表的时间段内,出现的所有点对。
每一个点对$(a,b)$有一个存在区间$[l,r]$,对于线段树上$[l,r]$覆盖的线段树节点,往它们里面都加入该点对。
对于查询操作,若在时间$i$询问$q$,就从根节点遍历到下标为$[i,i]$的叶子节点。在路上的每一个节点,都在它的上凸壳内进行一次三分(代入$q$),最后取所有经过的点的最大值即可。
为什么?因为在访问$[i,i]$的时候经过了一个节点$u$,那么$u$一定包含$[i,i]$。所以对所有经过节点三分,一定考虑到了询问$i$时还活着的所有点对。
维护上凸壳时,由于单调栈的模拟需要$a$递增,如果每一个节点插完之后自己再排序就太慢了。可以先离线记录所有的点对,按$a$递增排序,逐个插入线段树,这样就省去了每个节点内部的排序,因为插入的点的$a$一定不会小于整个线段树先前存在的任意一个$a$。
感觉是道神题orz
#include <cstdio>
#include <cstring>
using namespace std;
const int N=,INF=;
int n,h[N],tot,d[N],root,all,sum[N];
int f[N][][N/];
struct Edge{int v,next;}g[N*];
inline int min(int x,int y){return x<y?x:y;}
inline void upd(int &x,int y){if(y<x) x=y;}
inline void addEdge(int u,int v){g[++tot].v=v; g[tot].next=h[u]; h[u]=tot;}
inline int rd(){
char c=getchar(); int x=;
while(c<''||c>'') c=getchar(); x=c-'';
while(''<=(c=getchar())&&c<='') x=x*+c-'';
return x;
}
void init(){
for(int u=;u<=n;u++)
if(d[u]==) all++;
else if(!root) root=u;
for(int i=;i<=n;i++)
for(int j=;j<=;j++)
for(int k=,up=all/;k<=up;k++) f[i][j][k]=INF;
}
void dfs(int u,int fa){
if(d[u]==){
f[u][][]=f[u][][]=;
sum[u]=;
return;
}
for(int i=h[u],v;i;i=g[i].next)
if((v=g[i].v)!=fa){
dfs(v,u);
sum[u]+=sum[v];
}
int fson=;
for(int i=h[u],v;i;i=g[i].next)
if((v=g[i].v)!=fa){
if(!fson){
for(int j=,up=min(min(sum[u],sum[v]),all/);j<=up;j++){
f[u][][j]=min(f[v][][j],f[v][][j]+);
f[u][][j]=min(f[v][][j]+,f[v][][j]);
}
fson=;
continue;
}
int F0,F1;
for(int j=min(sum[u],all/);j>=;j--){
f[u][][j]+=min(f[v][][],f[v][][]+);
f[u][][j]+=min(f[v][][]+,f[v][][]);
for(int k=,upk=min(sum[v],j);k<=upk;k++){
upd(f[u][][j],f[u][][j-k]+min(f[v][][k],f[v][][k]+));
upd(f[u][][j],f[u][][j-k]+min(f[v][][k]+,f[v][][k]));
}
}
}
}
int main(){
n=rd();
for(int u,v,i=;i<n;i++){
u=rd(); v=rd();
addEdge(u,v); addEdge(v,u);
d[u]++; d[v]++;
}
if(n==){puts(""); return ;}
init();
if(all&) return ;
dfs(root,);
printf("%d\n",min(f[root][][all/],f[root][][all/]));
return ;
}
奇妙代码
【CF 678F】Lena and Queries的更多相关文章
- 【CF 710F】String Set Queries
在校内OJ上A了,没有加强制在线的东西..不放链接了. 这道题题意是维护一个字符串集合,支持三种操作: 1.加字符串 2.删字符串 3.查询集合中的所有字符串在给出的模板串中出现的次数 操作数\(m ...
- 【CF#338D】GCD Table
[题目描述] 有一张N,M<=10^12的表格,i行j列的元素是gcd(i,j) 读入一个长度不超过10^4,元素不超过10^12的序列a[1..k],问是否在某一行中出现过 [题解] 要保证g ...
- 【CF#303D】Rotatable Number
[题目描述] Bike是一位机智的少年,非常喜欢数学.他受到142857的启发,发明了一种叫做“循环数”的数. 如你所见,142857是一个神奇的数字,因为它的所有循环排列能由它乘以1,2,...,6 ...
- 【35.20%】【CF 706D】Vasiliy's Multiset
time limit per test 4 seconds memory limit per test 256 megabytes input standard input output standa ...
- 【CF 463F】Escape Through Leaf
题意 给你一棵 \(n\) 个点的树,每个节点有两个权值 \(a_i,b_i\). 从一个点 \(u\) 可以跳到以其为根的子树内的任意一点 \(v\)(不能跳到 \(u\) 自己),代价是 \(a_ ...
- 【CF 453A】 A. Little Pony and Expected Maximum(期望、快速幂)
A. Little Pony and Expected Maximum time limit per test 1 second memory limit per test 256 megabytes ...
- 【CF 585E】 E. Present for Vitalik the Philatelist
E. Present for Vitalik the Philatelist time limit per test 5 seconds memory limit per test 256 megab ...
- 【26.8%】【CF 46D】Parking Lot
time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...
- 【31.42%】【CF 714A】Meeting of Old Friends
time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...
随机推荐
- Oracl Over函数
Oracl Over函数 简介 在介绍Over之前, 必须提到开窗函数, 与 聚 合函数一样, 开窗函数也是对行集组进行聚合计算, 但是它不像普通聚合函数那样每组只返回一个值, 开窗函数可以为每组返回 ...
- error_reporting
有关error_reporting()函数: error_reporting() 设置 PHP 的报错级别并返回当前级别. ; 错误报告是按位的,或者将数字加起来得到想要的错误报告等级. ; E_AL ...
- lvs_dr
lvs_dr 实验需求(4台虚拟机) eth0 192.168.1.110 单网卡 client(可以使用windows浏览器代替,但会有缓存影响) eth0 192.168.1.186 单网卡 di ...
- es故障节点恢复后加入集群导致删除索引重新出现
es的每个shard下的文件都可以看做一个完整的lucene文件,shard数据目录下的segment文件包含了索引的分片数量,副本数量.es shard可以恢复,就是因为每个shard都包含了一份数 ...
- c语言中的#ifdef和#ifndef
#include "stdio.h"#include "conio.h"#define MAX#define MAXIMUM(x,y) (x>y)?x:y ...
- 如何使用JS实现banner图滚动
通过JS实现banner图的滚动主要是定时器的应用 先新建好banner图的几张图片,最后一张与第一张用同一个,保证滚动的不间断 改好样式,需注意所有图片要在同行显示,否则不能向左滚动 声明一个函数, ...
- Python中append和extend的区别
编者注:本文主要参考了<Python核心编程(第二版)> 网上有很多对这两个函数的区别讲解,但我觉得都讲的不是很清楚,记忆不深刻.这样解释清楚且容易记住. list.append(obje ...
- WPF: 深入理解 Weak Event 模型
在之前写的一篇文章(XAML: 自定义控件中事件处理的最佳实践)中,我们曾提到了在 .NET 中如果事件没有反注册,将会引起内存泄露.这主要是因为当事件源会对事件监听者产生一个强引用,导致事件监听者无 ...
- [Python Study Notes]cpu信息
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ...
- apache服务器绑定泛解析域名
<VirtualHost *:80> DocumentRoot "E:\web\bubuchu" ServerName bubuchu.com ServerAlias ...