贪心思想。将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+主席树维护前驱后驱】的更多相关文章

  1. PAT天梯赛练习题 L3-002. 堆栈(线段树查询第K大值或主席树)

    L3-002. 堆栈 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 大家都知道“堆栈”是一种“先进后出”的线性结构,基本操作有 ...

  2. HDU6621 K-th Closest Distance 第 k 小绝对值(主席树(统计范围的数有多少个)+ 二分 || 权值线段树+二分)

    题意:给一个数组,每次给 l ,r, p, k,问区间 [l, r] 的数与 p 作差的绝对值的第 k 小,这个绝对值是多少 分析:首先我们先分析单次查询怎么做: 题目给出的数据与多次查询已经在提示着 ...

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

  4. COGS 930. [河南省队2012] 找第k小的数 主席树

    主席树裸板子 #include<cstdio> #include<iostream> #include<algorithm> #define MAXN 100005 ...

  5. [xdoj1216]子树第k小(dfs序+主席树)

    解题关键:dfs序将树映射到区间,然后主席树求区间第k小,为模板题. #pragma comment(linker, "/STACK:1024000000,1024000000") ...

  6. 【9.22校内测试】【可持久化并查集(主席树实现)】【DP】【点双联通分量/割点】

    1 build1.1 Description从前有一个王国,里面有n 座城市,一开始两两不连通.现在国王将进行m 次命令,命令可能有两种,一种是在u 和v 之间修建道路,另一种是询问在第u 次命令执行 ...

  7. LCA+主席树 (求树上路径点权第k大)

      SPOJ 10628. Count on a tree (树上第k大,LCA+主席树) 10628. Count on a tree Problem code: COT You are given ...

  8. 【SPOJ】10628. Count on a tree(lca+主席树+dfs序)

    http://www.spoj.com/problems/COT/ (速度很快,排到了rank6) 这题让我明白了人生T_T 我知道我为什么那么sb了. 调试一早上都在想人生. 唉. 太弱. 太弱. ...

  9. 【bzoj3123】[Sdoi2013]森林 倍增LCA+主席树+启发式合并

    题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...

随机推荐

  1. discuz过滤词语无效

    1.是由于一些特殊的字导致serialize序列化错误.过滤词语在表 common_word中,序列化房子common_syscache的censor中,看看是否有特殊符号.

  2. 浅析Postgres中的并发控制(Concurrency Control)与事务特性(上)

    转载:https://www.cnblogs.com/flying-tiger/p/9567213.html#4121483#undefined PostgreSQL为开发者提供了一组丰富的工具来管理 ...

  3. 渗透测试===kali linux的安装

    方法一: kali linux 安装在本地的vitural box 或者 wm ware中 方法二: 安装在移动硬盘或者储存卡中,插到电脑就能用

  4. JavaBean的实用工具Lombok(省去get、set等方法)

    转:https://blog.csdn.net/ghsau/article/details/52334762 背景   我们在开发过程中,通常都会定义大量的JavaBean,然后通过IDE去生成其属性 ...

  5. python网络编程-进程间数据通信(Queue,Pipe ,managers)

    一:进程间数据交换方法 不同进程间内存是不共享的,要想实现两个进程间的数据交换,可以用以下方法: Queue,Pipe ,managers 1)Queue,使用方法跟threading里的queue差 ...

  6. day11作业

    一.选择题 1.B 2.D 3.AB 4.C 二.判断题 1.× 2.√ 三.简答题 1. 多态就是事物存在的多种形态. 提高程序的复用性,提高程序的可扩展性和可维护性. 2. 向上转型是指父类引用指 ...

  7. Python 的內建模块

    >>> import __builtin__>>> dir(__builtin__)['ArithmeticError', 'AssertionError', 'A ...

  8. gif处理

    UleadGIFAnimator-v5.05破解版 网盘地址:https://pan.baidu.com/s/1bpf6iVP 2017-02-19  10:39:58

  9. 根据条件批量删除document

    curl -H "Content-Type:application/json"  -XPOST http://localhost:9200/devopsrealinfo/_dele ...

  10. HA下的Spark集群工作原理解密

    实验环境: zookeeper-3.4.6 Spark:1.6.0 简介: 本篇博客将从以下几点组织文章: 一:Spark 构建高可用HA架构 二:动手实战构建高可用HA 三:提交程序测试HA 一:S ...