【10.10校内测试】【线段树维护第k小+删除】【lca+主席树维护前驱后驱】

贪心思想。将a排序后,对于每一个a,找到对应的删除m个后最小的b,每次更新答案即可。
如何删除才是合法并且最优的?首先,对于排了序的a,第$i$个那么之前就应该删除前$i-1$个a对应的b。剩下$m-i+1$可以删,那么在剩下的b中查找第$m-i+2$小即可。每次做完就删除当前a对应的b。
注意离散化。
还有数组不要开大了....
#include<bits/stdc++.h>
#define LL long long
using namespace std; void read(int &x) {
x = ; int t = ; char ch = getchar();
while(ch > '' || ch < '') { if(ch == '-') t = -; ch = getchar(); }
while(ch >= '' && ch <= '') {
x = x * + ch - '';
ch = getchar();
}
x = x * t;
} int a[], b[], n, m; struct Node {
int a, b;
int ida, idb;
} mat[];
bool cmp(Node a, Node b) { if(a.a == b.a) return a.b < b.b; return a.a < b.a; } int siz[], val[]; void modify(int nd, int l, int r, int pos, int d) {
if(l == r) {
siz[nd] += d;
return ;
}
int mid = (l + r) >> ;
if(pos <= mid) modify(nd << , l, mid, pos, d);
else modify(nd << | , mid + , r, pos, d);
siz[nd] = siz[nd << ] + siz[nd << | ];
} int query(int nd, int l, int r, int pos) {
if(l == r) return val[l];
int mid = (l + r) >> ;
if(pos <= siz[nd << ]) return query(nd << , l, mid, pos);
else return query(nd << | , mid + , r, pos - siz[nd << ]);
} int pos[];
void work() {
sort(b + , b + + n);
int q = unique(b + , b + + n) - b - ; memset(siz, , sizeof(siz));
sort(mat + , mat + + n, cmp);
for(int i = ; i <= n; i ++) {
pos[i] = lower_bound(b + , b + + q, mat[i].b) - b;
val[pos[i]] = mat[i].b;
modify(, , q, pos[i], );
} LL ans = ;
int r = min(mat[].b, query(, , q, m + ));
ans = 1ll * mat[].a * r;
for(int i = ; i <= m; i ++) {
modify(, , q, pos[i], -);
int res = m - i + ;
r = query(, , q, res);
if(mat[i + ].b < r) r = mat[i + ].b;
LL now = 1ll * mat[i + ].a * r;
ans = max(ans, now);
} printf("%lld\n", ans);
} int main() {
freopen("d.in", "r", stdin);
freopen("d.out", "w", stdout);
int T;
scanf("%d", &T);
while(T --) {
read(n); read(m);
for(int i = ; i <= n; i ++) {
read(mat[i].a); read(mat[i].b);
b[i] = mat[i].b;
}
work();
}
return ;
}

依旧是数据结构。我们发现,对于一个点集,它们一定有一个lca,而满足包含所有点的最小点集就是所有点到这个lca的链上的所有点。再加上题目要求最小的$abs(a[u]-r)$,就是用每条链上r的前驱和后驱来更新答案。
用主席树维护即可。每个结点的版本是由它的父亲结点转移过来。这样做查询的时候直接取出当前结点和lca的父亲结点的版本即可。
关于这个前驱和后驱的计算可以学习一下。
#include<bits/stdc++.h>
#define LL long long
using namespace std; const int maxn = 1e9; void read(int &x) {
x = ; int t = ; char ch = getchar();
while(ch > '' || ch < '') { if(ch == '-') t = -; ch = getchar(); }
while(ch >= '' && ch <= '') {
x = x * + ch - '';
ch = getchar();
}
x = x * t;
} int n, q, type; struct Node {
int v, nex;
Node(int v = , int nex = ) :
v(v), nex(nex) { }
} Edge[]; int h[], stot;
void add(int u, int v) {
Edge[++stot] = Node(v, h[u]);
h[u] = stot;
} int sum[*], ls[*], rs[*], tail;
inline int newnode(int x) {
sum[++tail] = sum[x];
ls[tail] = ls[x]; rs[tail] = rs[x];
return tail;
} inline void update(int nd) {
sum[nd] = sum[ls[nd]] + sum[rs[nd]];
} int insert(int nd, int l, int r, LL pos) {
nd = newnode(nd);
sum[nd] ++;
if(l == r) return nd;
int mid = (l + r) >> ;
if(pos <= mid) ls[nd] = insert(ls[nd], l, mid, pos);
else rs[nd] = insert(rs[nd], mid + , r, pos);
update(nd);
return nd;
} int queryl(int nd1, int nd2, int l, int r, int pos) {
if(sum[nd1] == sum[nd2]) return ;///这个结点下面没有新的点
if(l == r) return l;
int mid = (l + r) >> ;
if(pos <= mid) return queryl(ls[nd1], ls[nd2], l, mid, pos);
else {
int tmp = queryl(rs[nd1], rs[nd2], mid + , r, pos);////尽量往靠近pos的地方走
if(tmp) return tmp;///如果走不到就尽量往mid走
else return queryl(ls[nd1], ls[nd2], l, mid, mid);
}
} int queryr(int nd1, int nd2, int l, int r, int pos) {
if(sum[nd1] == sum[nd2]) return ;
if(l == r) return l;
int mid = (l + r) >> ;
if(pos > mid) return queryr(rs[nd1], rs[nd2], mid + , r, pos);
else {
int tmp = queryr(ls[nd1], ls[nd2], l, mid, pos);
if(tmp) return tmp;
else return queryr(rs[nd1], rs[nd2], mid + , r, mid);
}
} int dep[], jum[][];
int lca(int u, int v) {
if(dep[u] < dep[v]) swap(u, v);
int t = dep[u] - dep[v];
for(int p = ; t; t >>= , p ++)
if(t & ) u = jum[u][p];
if(u == v) return u;
for(int p = ; p >= ; p --)
if(jum[u][p] != jum[v][p]) u = jum[u][p], v = jum[v][p];
return jum[u][];
} int rt[], a[];
void dfs(int u, int f) {
jum[u][] = f;
for(int i = ; i < ; i ++)
jum[u][i] = jum[jum[u][i - ]][i - ];
dep[u] = dep[f] + ;
rt[u] = insert(rt[f], , maxn, a[u]);
for(int i = h[u]; i; i = Edge[i].nex) {
int v = Edge[i].v;
if(v == f) continue;
dfs(v, u);
}
} int x[], p[];
int main() {
freopen("e.in", "r", stdin);
freopen("e.out", "w", stdout);
scanf("%d%d%d", &n, &q, &type);
for(int i = ; i <= n; i ++) read(a[i]);
for(int i = ; i < n; i ++) {
int u, v;
read(u); read(v);
add(u, v); add(v, u);
}
dfs(, );
int lastans = ;
for(int i = ; i <= q; i ++) {
int r, k;
scanf("%d%d", &r, &k);
for(int j = ; j <= k; j ++) {
read(x[j]);
p[j] = (x[j] - + lastans * type) % n + ;
}
int l = p[];
for(int j = ; j <= k; j ++)
l = lca(l, p[j]);
l = jum[l][];
int res = maxn, tmp;
for(int j = ; j <= k; j ++) {
tmp = queryl(rt[l], rt[p[j]], , maxn, r);
if(tmp && r - tmp < res) res = r - tmp;
tmp = queryr(rt[l], rt[p[j]], , maxn, r);
if(tmp && tmp - r < res) res = tmp - r;
}
printf("%d\n", res);
lastans = res;
}
return ;
}
【10.10校内测试】【线段树维护第k小+删除】【lca+主席树维护前驱后驱】的更多相关文章
- PAT天梯赛练习题 L3-002. 堆栈(线段树查询第K大值或主席树)
L3-002. 堆栈 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 大家都知道“堆栈”是一种“先进后出”的线性结构,基本操作有 ...
- HDU6621 K-th Closest Distance 第 k 小绝对值(主席树(统计范围的数有多少个)+ 二分 || 权值线段树+二分)
题意:给一个数组,每次给 l ,r, p, k,问区间 [l, r] 的数与 p 作差的绝对值的第 k 小,这个绝对值是多少 分析:首先我们先分析单次查询怎么做: 题目给出的数据与多次查询已经在提示着 ...
- SPOJ 10628. Count on a tree (树上第k大,LCA+主席树)
10628. Count on a tree Problem code: COT You are given a tree with N nodes.The tree nodes are number ...
- COGS 930. [河南省队2012] 找第k小的数 主席树
主席树裸板子 #include<cstdio> #include<iostream> #include<algorithm> #define MAXN 100005 ...
- [xdoj1216]子树第k小(dfs序+主席树)
解题关键:dfs序将树映射到区间,然后主席树求区间第k小,为模板题. #pragma comment(linker, "/STACK:1024000000,1024000000") ...
- 【9.22校内测试】【可持久化并查集(主席树实现)】【DP】【点双联通分量/割点】
1 build1.1 Description从前有一个王国,里面有n 座城市,一开始两两不连通.现在国王将进行m 次命令,命令可能有两种,一种是在u 和v 之间修建道路,另一种是询问在第u 次命令执行 ...
- LCA+主席树 (求树上路径点权第k大)
SPOJ 10628. Count on a tree (树上第k大,LCA+主席树) 10628. Count on a tree Problem code: COT You are given ...
- 【SPOJ】10628. Count on a tree(lca+主席树+dfs序)
http://www.spoj.com/problems/COT/ (速度很快,排到了rank6) 这题让我明白了人生T_T 我知道我为什么那么sb了. 调试一早上都在想人生. 唉. 太弱. 太弱. ...
- 【bzoj3123】[Sdoi2013]森林 倍增LCA+主席树+启发式合并
题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...
随机推荐
- Servlet笔记2--模拟Servlet本质、第一个Servlet程序、将响应结果输出到浏览器中
以下代码均非IDE开发,所以都不规范,仅供参考 模拟Servlet本质: 模拟Servlet接口: /* SUN公司制定的JavaEE规范:Servlet规范 Servlet接口是Servlet规范中 ...
- Linux下C程序的反汇编【转】
转自:http://blog.csdn.net/u011192270/article/details/50224267 前言:本文主要介绍几种反汇编的方法. gcc gcc的完整编译过程大致为:预处理 ...
- 【驱动】USB驱动·入门【转】
转自:http://www.cnblogs.com/lcw/p/3159371.html Preface USB是目前最流行的系统总线之一.随着计算机周围硬件的不断扩展,各种设备使用不同的总线接口,导 ...
- php修改文件上传大小限制
上传一个20M文件的时候php报如下错误,是php上传文件大小限制引起 POST Content-Length of 19248654 bytes exceeds the limit of 83886 ...
- 洛谷P2812校园网络
传送门啦 其实这个题只要读懂分析好题意就不是很难. 就是将一个有向图进行缩点操作,把一个强连通分量看成一个点,求入度为 0 的点和出度为 0 的点各有多少. 在这里先向大家推荐两个题目,建议大家先去看 ...
- CentOS/Linux 网卡设置 IP地址配置
CentOS/Linux下设置IP地址 1:临时修改:1.1:修改IP地址# ifconfig eth0 192.168.100.100 1.2:修改网关地址# route add default g ...
- numpy数学计算
1.求范数 np.linalg.norm norm(x, ord=None, axis=None, keepdims=False) 范数理论的一个小推论告诉我们:ℓ1≥ℓ2≥ℓ∞
- 个人理解的Windows漏洞利用技术发展史
大概四.五年前,看过陈皓的酷壳上面的一篇文章,上面有一句话我一直记得,是关于学习技术的心得和态度的. 要了解技术就一定需要了解整个计算机的技术历史发展和进化路线.因为,你要朝着球运动的轨迹去,而不是朝 ...
- PowerTool x64驱动模块逆向分析(持续更新)
比赛打完了,来继续搞了,因为那个主动防御正在写,所以想找找思路正好想到可以来逆向一下PT的驱动模块看看pt大大是怎么写的程序. PT x64版本的驱动模块是这个kEvP64.sys. 0x0 先来看看 ...
- SQL中format()函数对应的格式
http://www.cnbeta.com/articles/tech/632057.htm