题意:链上带修第k大。

这毒瘤题。。。别看题意只有7个字,能把我吊打死。。。

介绍其中两种做法好了。其实思想上是一样的。

对于每一个点,建立权值线段树,维护它到根路径上的所有权值。

一条路径上的点集就是x + y - z - fa z,此处z是lca x y

这样查询就可以轻易做到了。怎么建出来呢?

考虑每个点都要在它的子树中插入。那么我们搞出DFS序来,子树就是上面的一段区间。

我们就要对于这个DFS序,支持区间加(插入),单点求值。很容易想到树状数组+差分。

那么我们就用树状数组维护差分后的值域线段树,这样就是单点修改和区间求和了。

也就是树状数组套线段树...

具体实现上,查询操作有点小技巧。因为要同时查4个位置然后加加减减,每个位置又会涉及查询log棵线段树,所以就用一个now i来维护i版本的线段树当前走到的节点,用一个栈来存要用到的线段树以便更新。

然后修改操作嘛,就是删除之前的再加上新的。

时间复杂度nlog2n。

 #include <cstdio>
#include <algorithm> const int N = , lm = 1e8, M = ; struct Edge {
int nex, v;
}edge[N << ]; int top; int e[N], p[N], num, val[N], pos[N], n, ed[N], fa[N][], tot, pw[N], d[N], rt[N], now[N], tp;
int sum[M], ls[M], rs[M];
bool vis[N]; inline void add(int x, int y) {
top++;
edge[top].v = y;
edge[top].nex = e[x];
e[x] = top;
return;
} void DFS(int x, int f) {
fa[x][] = f;
d[x] = d[f] + ;
pos[x] = ++num;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y != f) {
DFS(y, x);
}
}
ed[x] = num;
return;
} void Add(int p, int v, int l, int r, int &o) {
if(!o) {
o = ++tot;
}
if(l == r) {
sum[o] += v;
return;
}
int mid = (l + r) >> ;
if(p <= mid) {
Add(p, v, l, mid, ls[o]);
}
else {
Add(p, v, mid + , r, rs[o]);
}
sum[o] = sum[ls[o]] + sum[rs[o]];
return;
} inline void insert(int id, int p, int v) {
for(int i = id; i <= num; i += (i & (-i))) {
Add(p, v, , lm, rt[i]);
}
return;
} inline int lca(int x, int y) {
if(d[x] > d[y]) {
std::swap(x, y);
}
int t = pw[n];
while(t >= && d[y] > d[x]) {
if(d[fa[y][t]] >= d[x]) {
y = fa[y][t];
}
t--;
}
if(x == y) {
return x;
}
t = pw[n];
while(t >= && fa[x][] != fa[y][]) {
if(fa[x][t] != fa[y][t]) {
x = fa[x][t];
y = fa[y][t];
}
t--;
}
return fa[x][];
} inline int ask(int k, int x, int y) {
int z = lca(x, y);
if(d[x] + d[y] - * d[z] + < k) {
return -;
}
// x + y - z - fa[z]
int w = fa[z][];
x = pos[x], y = pos[y], z = pos[z], w = pos[w];
for(int i = x; i >= ; i -= (i & (-i))) {
if(!vis[i]) {
vis[i] = ;
p[++tp] = i;
now[i] = rt[i];
}
}
for(int i = y; i >= ; i -= (i & (-i))) {
if(!vis[i]) {
vis[i] = ;
p[++tp] = i;
now[i] = rt[i];
}
}
for(int i = z; i >= ; i -= (i & (-i))) {
if(!vis[i]) {
vis[i] = ;
p[++tp] = i;
now[i] = rt[i];
}
}
for(int i = w; i >= ; i -= (i & (-i))) {
if(!vis[i]) {
vis[i] = ;
p[++tp] = i;
now[i] = rt[i];
}
}
//
int l = , r = lm;
while(l < r) {
int mid = (l + r) >> , s = ;
for(int i = x; i >= ; i -= i & (-i)) {
s += sum[rs[now[i]]];
}
for(int i = y; i >= ; i -= i & (-i)) {
s += sum[rs[now[i]]];
}
for(int i = z; i >= ; i -= i & (-i)) {
s -= sum[rs[now[i]]];
}
for(int i = w; i >= ; i -= i & (-i)) {
s -= sum[rs[now[i]]];
}
if(k <= s) { // rs
for(int i = ; i <= tp; i++) {
now[p[i]] = rs[now[p[i]]];
}
l = mid + ;
}
else { // ls
k -= s;
for(int i = ; i <= tp; i++) {
now[p[i]] = ls[now[p[i]]];
}
r = mid;
}
}
for(int i = ; i <= tp; i++) {
vis[p[i]] = ;
}
tp = ;
return r;
} inline void init() {
for(int i = ; i <= n; i++) {
pw[i] = pw[i >> ] + ;
}
for(int j = ; j <= pw[n]; j++) {
for(int i = ; i <= n; i++) {
fa[i][j] = fa[fa[i][j - ]][j - ];
}
}
return;
} int main() {
int q;
scanf("%d%d", &n, &q);
for(int i = ; i <= n; i++) {
scanf("%d", &val[i]);
}
for(int i = , x, y; i < n; i++) {
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
// prework DFS(, );
init();
for(int i = ; i <= n; i++) {
// [pos[i], ed[i]] insert val[i] 1
insert(pos[i], val[i], );
insert(ed[i] + , val[i], -);
} for(int i = , f, x, y; i <= q; i++) {
scanf("%d%d%d", &f, &x, &y);
if(f == ) { // change val[x] = y
// [pos[x] ed[x]] insert val[x]
insert(pos[x], val[x], -);
insert(ed[x] + , val[x], );
insert(pos[x], y, );
insert(ed[x] + , y, -);
val[x] = y;
}
else { /// ask fth
int t = ask(f, x, y);
if(t == -) {
puts("invalid request!");
}
else {
printf("%d\n", t);
}
}
}
return ;
}

AC代码

接下来是线段树套线段树的写法。

离散化之后外层值域线段树,内层线段树每个点按照DFS序维护,该点到根的路径上,有多少点的权值在外层树这个范围内。

查询的时候也是值域线段树上二分。利用lca转化成4个内层线段树单点求值再加加减减。

建树的时候,每个点要在外层树上从上往下log个内层树中插入。内层树中要在它的子树插入,又是一段区间。

修改就是跟建树差不多的操作,删去旧的再加上新的。

开了O2还慢的飞起...好歹是过了。

时间复杂度同上。

 // luogu-judger-enable-o2
#include <cstdio>
#include <algorithm> const int N = , M = ; struct Node {
int f, x, y;
}node[N]; struct Edge {
int nex, v;
}edge[N << ]; int top; int e[N], n, num, tot, pw[N], pos[N], ed[N], fa[N][], d[N], rt[N << ], temp, val[N], X[N << ];
int tag[M], ls[M], rs[M], sum[M]; inline void add(int x, int y) {
top++;
edge[top].v = y;
edge[top].nex = e[x];
e[x] = top;
return;
} inline void pushdown(int l, int r, int o) {
if(!tag[o]) {
return;
}
if(!ls[o]) {
ls[o] = ++tot;
}
if(!rs[o]) {
rs[o] = ++tot;
}
tag[ls[o]] += tag[o];
tag[rs[o]] += tag[o];
int mid = (l + r) >> ;
sum[ls[o]] += tag[o] * (mid - l + );
sum[rs[o]] += tag[o] * (r - mid);
tag[o] = ;
return;
} void DFS(int x, int f) {
fa[x][] = f;
d[x] = d[f] + ;
pos[x] = ++num;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y != f) {
DFS(y, x);
}
}
ed[x] = num;
return;
} inline void init() {
for(int i = ; i <= n; i++) {
pw[i] = pw[i >> ] + ;
}
for(int j = ; j <= pw[n]; j++) {
for(int i = ; i <= n; i++) {
fa[i][j] = fa[fa[i][j - ]][j - ];
}
}
return;
} inline int lca(int x, int y) {
if(d[x] > d[y]) {
std::swap(x, y);
}
int t = pw[n];
while(t >= && d[y] > d[x]) {
if(d[fa[y][t]] >= d[x]) {
y = fa[y][t];
}
t--;
}
if(x == y) {
return x;
}
t = pw[n];
while(t >= && fa[x][] != fa[y][]) {
if(fa[x][t] != fa[y][t]) {
x = fa[x][t];
y = fa[y][t];
}
t--;
}
return fa[x][];
} void Add(int L, int R, int v, int l, int r, int &o) {
//printf("add : %d %d %d %d %d %d \n", L, R, v, l, r, o);
if(!o) {
o = ++tot;
}
if(L <= l && r <= R) {
tag[o] += v;
sum[o] += (r - l + ) * v;
return;
}
pushdown(l, r, o);
int mid = (l + r) >> ;
if(L <= mid) {
Add(L, R, v, l, mid, ls[o]);
}
if(mid < R) {
Add(L, R, v, mid + , r, rs[o]);
}
sum[o] = sum[ls[o]] + sum[rs[o]];
return;
} void insert(int L, int R, int v, int p, int l, int r, int o) {
//printf("insert val [%d %d] \n", l, r);
Add(L, R, v, , n, rt[o]);
if(l == r) {
return;
}
int mid = (l + r) >> ;
if(p <= mid) {
insert(L, R, v, p, l, mid, o << );
}
else {
insert(L, R, v, p, mid + , r, o << | );
}
return;
} int getSum(int p, int l, int r, int o) {
if(!o) {
return ;
}
if(l == r) {
return sum[o];
}
int mid = (l + r) >> ;
pushdown(l, r, o);
if(p <= mid) {
return getSum(p, l, mid, ls[o]);
}
else {
return getSum(p, mid + , r, rs[o]);
}
} int Ask(int k, int x, int y, int z, int w, int l, int r, int o) {
if(l == r) {
return r;
}
int s = ;
s += getSum(x, , n, rt[o << | ]);
s += getSum(y, , n, rt[o << | ]);
s -= getSum(z, , n, rt[o << | ]);
if(w) {
s -= getSum(w, , n, rt[o << | ]);
}
int mid = (l + r) >> ;
if(k <= s) {
return Ask(k, x, y, z, w, mid + , r, o << | );
}
else {
k -= s;
return Ask(k, x, y, z, w, l, mid, o << );
}
} inline int ask(int k, int x, int y) {
int z = lca(x, y);
if(d[x] + d[y] - d[z] * + < k) {
return -;
}
int w = fa[z][];
x = pos[x];
y = pos[y];
z = pos[z];
w = pos[w];
return Ask(k, x, y, z, w, , temp, );
} int main() {
int q;
scanf("%d%d", &n, &q);
for(int i = ; i <= n; i++) {
scanf("%d", &val[i]);
X[++temp] = val[i];
}
for(int i = , x, y; i < n; i++) {
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
for(int i = ; i <= q; i++) {
scanf("%d%d%d", &node[i].f, &node[i].x, &node[i].y);
if(node[i].f == ) {
X[++temp] = node[i].y;
}
}
// prework
std::sort(X + , X + temp + );
temp = std::unique(X + , X + temp + ) - X - ;
for(int i = ; i <= n; i++) {
val[i] = std::lower_bound(X + , X + temp + , val[i]) - X;
}
for(int i = ; i <= q; i++) {
if(node[i].f == ) {
node[i].y = std::lower_bound(X + , X + temp + , node[i].y) - X;
}
} DFS(, );
init();
for(int i = ; i <= n; i++) {
insert(pos[i], ed[i], , val[i], , temp, );
}
for(int i = , f, x, y; i <= q; i++) {
f = node[i].f;
x = node[i].x;
y = node[i].y;
if(f == ) { // change
insert(pos[x], ed[x], -, val[x], , temp, );
insert(pos[x], ed[x], , y, , temp, );
val[x] = y;
}
else { // ask fth
int t = ask(f, x, y);
if(t == -) {
puts("invalid request!");
}
else {
printf("%d\n", X[t]);
}
}
}
return ;
}

AC代码

写的有点乱...

洛谷P4175 网络管理的更多相关文章

  1. 洛谷 P4175: bzoj 1146: [CTSC2008]网络管理

    令人抓狂的整体二分题.根本原因还是我太菜了. 在学校写了一个下午写得头晕,回家里重写了一遍,一个小时就写完了--不过还是太慢. 题目传送门:洛谷P4175. 题意简述: 一棵 \(n\) 个结点的树, ...

  2. 洛谷 P4175 [CTSC2008]网络管理 解题报告

    P4175 [CTSC2008]网络管理 题目描述 带修改树上链的第\(k\)大 输入输出格式 输入格式: 第一行为两个整数\(N\)和\(Q\),分别表示路由器总数和询问的总数. 第二行有\(N\) ...

  3. 洛谷P4175 - [CTSC2008]网络管理

    Portal Description 给出一棵\(n(n\leq8\times10^4)\)个点的带点权的树,进行\(m(m\leq8\times10^4)\)次操作,操作有两种: 修改一个点的点权. ...

  4. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

  5. 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.

    没有上司的舞会  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...

  6. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...

  7. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

  8. 洛谷P1710 地铁涨价

    P1710 地铁涨价 51通过 339提交 题目提供者洛谷OnlineJudge 标签O2优化云端评测2 难度提高+/省选- 提交  讨论  题解 最新讨论 求教:为什么只有40分 数组大小一定要开够 ...

  9. 洛谷P1371 NOI元丹

    P1371 NOI元丹 71通过 394提交 题目提供者洛谷OnlineJudge 标签云端评测 难度普及/提高- 提交  讨论  题解 最新讨论 我觉得不需要讨论O long long 不够 没有取 ...

随机推荐

  1. Oracle pivot行转列函数案例

    with temp as( select '湖北省' province,'武汉市' city,'第一' ranking from dual union all select '湖北省' provinc ...

  2. centOS 7下无法启动网络(service network start)错误解决办法

    今天在centOS 7下更改完静态ip后发现network服务重启不了,翻遍了网络,尝试了各种方法,终于解决了. 现把各种解决方法归纳整理,希望能让后面的同学少走点歪路... 首先看问题:执行serv ...

  3. netstat -na 查看有大量TIME_WAIT解决办法(修改内核参数)

    # netstat -an|awk '/tcp/ {print $6}'|sort|uniq -c      16 CLOSING     130 ESTABLISHED     298 FIN_WA ...

  4. js数组中两个有相同删除一个

    for (var i = 0; i < project.Before.length; i++) {                    var j = 0;                   ...

  5. 在web-inf外面 使用的是绝对路径进行访问 “/”表示访问文件夹 一层一层方式 我们在windos下访问文件夹也是一层一层的访问

  6. Uncaught SyntaxError: Unexpected token export

    开发过程中遇到这个错误,虽然不影响使用,但是每次浏览器控制台都会有错误输出,看起来十分不舒服,故翻阅资料发现是因为浏览器虽然支持了es6,但是不支持es6的Module直接使用,需要在script标签 ...

  7. 【数学建模】day08-数理统计III

    2. 回归分析 回归分析与曲线拟合区分. 曲线拟合是,根据得到的若干有关变量的一组数据,寻找因变量与(一个或几个)自变量之间的一个函数,使这个函数对那组数据拟合得好.通常,函数的形式可以由经验.先验知 ...

  8. mysql操作命令

    一.MySQL连接命令 mysql-u:指定用户-p:指定密码-S:指定socket文件-P:指定端口-h:指定主机域-e:指定sql语句 mysql> status \s 查看状态 mysql ...

  9. 基准对象object中的基础类型----列表 (四)

    object有如下子类: CLASSES object basestring str unicode buffer bytearray classmethod complex dict enumera ...

  10. [NOI2002] 贪吃的九头龙

    题目类型:树形DP 传送门:>Here< 题意:有一只九头龙要吃了一颗树,给出一棵\(N\)个节点的带边权的树.九头龙有\(M\)个头,其中一个是大头,大头要吃恰好\(K\)个节点,其他头 ...