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的更多相关文章

  1. 【CF 710F】String Set Queries

    在校内OJ上A了,没有加强制在线的东西..不放链接了. 这道题题意是维护一个字符串集合,支持三种操作: 1.加字符串 2.删字符串 3.查询集合中的所有字符串在给出的模板串中出现的次数 操作数\(m ...

  2. 【CF#338D】GCD Table

    [题目描述] 有一张N,M<=10^12的表格,i行j列的元素是gcd(i,j) 读入一个长度不超过10^4,元素不超过10^12的序列a[1..k],问是否在某一行中出现过 [题解] 要保证g ...

  3. 【CF#303D】Rotatable Number

    [题目描述] Bike是一位机智的少年,非常喜欢数学.他受到142857的启发,发明了一种叫做“循环数”的数. 如你所见,142857是一个神奇的数字,因为它的所有循环排列能由它乘以1,2,...,6 ...

  4. 【35.20%】【CF 706D】Vasiliy's Multiset

    time limit per test 4 seconds memory limit per test 256 megabytes input standard input output standa ...

  5. 【CF 463F】Escape Through Leaf

    题意 给你一棵 \(n\) 个点的树,每个节点有两个权值 \(a_i,b_i\). 从一个点 \(u\) 可以跳到以其为根的子树内的任意一点 \(v\)(不能跳到 \(u\) 自己),代价是 \(a_ ...

  6. 【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 ...

  7. 【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 ...

  8. 【26.8%】【CF 46D】Parking Lot

    time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...

  9. 【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 ...

随机推荐

  1. 安卓studio导入jra包和so包,百度地图so包加载

    导入so包 这个我只接受测试可用的一种方法 第一步:把so包放在libs目录下,可以是文件夹也可以是单独的一个个so文件 然后在src同级的目录下找到build.gradle文件下如下信息 sourc ...

  2. java数组基础

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  3. MySQL基于binlog主从复制

    MySQL复制介绍 默认情况 下复制是异步进行的,从库也不需要一直连接到主库来同步数据 MySQL复制的数据粒度可以是主实例上所有的数据库,也可以是指定的一个或多个数据库 ,也可以是一个数据库里的指定 ...

  4. Ubantu搭建FTP

    1.安装并启动 FTP 服务 安装 VSFTPD 使用 apt-get 安装 vsftpd kylin@kylin:~$ sudo apt-get install vsftpd -y [sudo] p ...

  5. 取IP的几个方法

    ifconfig eth0|grep " inet add"|cut -d":" -f2|cut -d " " -f1 ifconfig e ...

  6. 解决spring-boot启动中碰到的问题:Cannot determine embedded database driver class for database type NONE

    问题 如下: 2017-07-16 08:50:57.436  INFO 13524 --- [           main] c.p.p.web.PointshopWebApplication   ...

  7. xDB and sitecore 8 hardware Recommendations

    xDB and sitecore 8 hardware Recommendations as below: xDB hardware guidelines https://doc.sitecore.n ...

  8. windows下cmd常用

    windows下cmd常用 shutdown -s -t 2------2秒后关机 加上-f选项意思是强制执行 shutdown -r -t 2------2秒后重启 加上-f选项意思是强制执行 lo ...

  9. python 之协程

    协程: 协程,又称微线程.  是一种用户态的轻量级线程(存在一个线程中,所以没有上下文切换,与同步) 无需线程上下文切换的开销 在线程中,线程切换时需要记住上下文 无需原子操作及同步的开销 没有锁了, ...

  10. 记录下直接在git里读取出差异并打包的代码

    一行命令: git diff --name-only HEAD commit_id | xargs tar -zcvf diff_head.tar.gz 这里的HEAD可以理解为最新的版本 HEAD本 ...