CERC 2014 Pork barrel

Problem :

n个点m条边有边权的无向图,有q个询问,每次询问权值在[L,R]内的边组成的最小生成树的权值和,强制在线。

n <= 1000, m <= 100000, q <= 100000

Solution :

参考了网上的一份题解

按照边权从大到小加入边,用LCT来维护最小生成树。再用一棵权值主席树,第i棵主席树记录表示权值大于等于 i 的边所构成的最小生成树边权和。

对于每个询问[L, R]直接在第L棵主席树的[L ,R]区间内统计答案。

对于每个询问[L, R],要将端点离散化成对应的边权表示,要注意离散化后的区间应被原来的区间包含,而不是包含原来的区间。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <queue>
#include <cassert>
using namespace std;
#define f(i, x, y) for (int i = x; i <= y; ++i)
#define fd(i, x, y) for (int i = x; i >= y; --i)
#define rep(i, x, y) for (int i = x; i <= y; ++i)
#define repd(i, x, y) for (int i = x; i >= y; --i) const int INF = 1e9 + 7;
const int N = 300008;
const int NN = N * 100;
int n, m, q; void read(int &x)
{
char ch;
for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar());
x = 0;
for (; ch >= '0' && ch <= '9'; ch = getchar())
x = x * 10 + ch - '0';
}
struct edge
{
int u, v, w;
bool operator < (const edge &b) const
{
return w > b.w;
}
}eg[N];
int fa[N], c[N][2], val[N], mx[N], rev[N], st[N];
int root[N], rtId[N], ls[NN], rs[NN];
long long tag[NN];
int num, total;
int p[N];
int tot; bool isroot(int x)
{
return c[fa[x]][0] != x && c[fa[x]][1] != x;
}
void pushup(int x)
{
int l = c[x][0], r = c[x][1];
mx[x] = x;
if (val[mx[l]] > val[mx[x]]) mx[x] = mx[l];
if (val[mx[r]] > val[mx[x]]) mx[x] = mx[r];
}
void pushdown(int x)
{
int l = c[x][0], r = c[x][1];
if (rev[x])
{
if (l) rev[l] ^= 1;
if (r) rev[r] ^= 1;
rev[x] ^= 1;
swap(c[x][0], c[x][1]);
}
}
void rotate(int x)
{
int y = fa[x], z = fa[y], l, r;
if (c[y][0] == x) l = 0; else l = 1; r = l ^ 1;
if (!isroot(y))
{
if (c[z][0] == y) c[z][0] = x; else c[z][1] = x;
}
fa[x] = z; fa[y] = x; fa[c[x][r]] = y;
c[y][l] = c[x][r]; c[x][r] = y;
pushup(y); pushup(x);
}
void splay(int x)
{
int top = 0; st[++top] = x;
for (int i = x; !isroot(i); i = fa[i]) st[++top] = fa[i];
while (top) pushdown(st[top--]);
while (!isroot(x))
{
int y = fa[x], z = fa[y];
if (!isroot(y))
{
if (c[y][0] == x ^ c[z][0] == y) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x)
{
for (int t = 0; x; t = x, x = fa[x])
{
splay(x);
c[x][1] = t;
pushup(x);
}
}
void rever(int x)
{
access(x); splay(x); rev[x] ^= 1;
}
void link(int u, int v)
{
rever(u); fa[u] = v;
}
void cut(int u, int v)
{
rever(u); access(v); splay(v); fa[c[v][0]] = 0; c[v][0] = 0; pushup(v);
}
int find(int u)
{
access(u); splay(u);
while (c[u][0]) u = c[u][0];
return u;
}
int query(int u, int v)
{
rever(u); access(v); splay(v); return mx[v];
}
void build(int &rt, int l, int r)
{
rt = ++total;
ls[rt] = rs[rt] = tag[rt] = 0;
if (l == r) return;
int m = l + r >> 1;
build(ls[rt], l, m);
build(rs[rt], m + 1, r);
}
void insert(int &rt, int last, int pos, int val, int l, int r)
{
rt = ++total;
ls[rt] = ls[last]; rs[rt] = rs[last]; tag[rt] = tag[last];
if (l == r)
{
tag[rt] += val;
return;
}
int m = l + r >> 1;
if (pos <= m) insert(ls[rt], ls[last], pos, val, l, m);
if (m < pos) insert(rs[rt], rs[last], pos, val, m + 1, r);
tag[rt] = tag[ls[rt]] + tag[rs[rt]];
}
long long query(int rt, int L, int R, int l, int r)
{
if (L <= l && r <= R)
{
return tag[rt];
}
long long res = 0;
int m = l + r >> 1;
if (L <= m) res += query(ls[rt], L, R, l, m);
if (m < R) res += query(rs[rt], L, R, m + 1, r);
return res;
}
void init()
{
read(n); read(m);
for (int i = 1; i <= m; ++i)
{
read(eg[i].u); read(eg[i].v); read(eg[i].w);
p[i] = eg[i].w;
}
sort(p + 1, p + m + 1);
tot = unique(p + 1, p + m + 1) - p - 1;
for (int i = 1; i <= m; ++i)
eg[i].w = lower_bound(p + 1, p + tot + 1, eg[i].w) - p;
}
void clear()
{
for (int i = 1; i <= num; ++i) root[i] = 0;
for (int i = 1; i <= tot + 5; ++i) rtId[i] = 0;
for (int i = 1; i <= n + m; ++i)
{
fa[i] = c[i][0] = c[i][1] = val[i] = mx[i] = rev[i] = 0;
}
num = total = 0;
}
void work()
{
build(root[0], 1, tot);
sort(eg + 1, eg + m + 1);
for (int i = 1; i <= m; ++i)
{
int u = eg[i].u, v = eg[i].v, w = eg[i].w;
if (find(u) == find(v))
{
int t = query(u, v);
cut(t, eg[t - n].u);
cut(t, eg[t - n].v);
rtId[w] = ++num;
insert(root[num], root[num - 1], val[t], -p[val[t]], 1, tot);
}
val[i + n] = w; mx[i + n] = i + n;
link(i + n, u);
link(i + n, v);
rtId[w] = ++num;
insert(root[num], root[num - 1], w, p[w], 1, tot);
}
}
void solve()
{
read(q);
int ans = 0;
for (int i = 1; i <= q; ++i)
{
int u, v;
read(u); read(v);
u -= ans; v -= ans;
int l = lower_bound(p + 1, p + tot + 1, u) - p;
int r = upper_bound(p + 1, p + tot + 1, v) - p - 1;
if (r == tot + 1) r = tot;
ans = query(root[rtId[l]], l, r, 1, tot);
cout << ans << endl;
}
}
int main()
{
int T; read(T);
for (int cas = 1; cas <= T; ++cas)
{
init();
clear();
work();
solve();
}
}

CERC 2014 (动态树+主席树)的更多相关文章

  1. 线段树简单入门 (含普通线段树, zkw线段树, 主席树)

    线段树简单入门 递归版线段树 线段树的定义 线段树, 顾名思义, 就是每个节点表示一个区间. 线段树通常维护一些区间的值, 例如区间和. 比如, 上图 \([2, 5]\) 区间的和, 为以下区间的和 ...

  2. 学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))

    函数式线段树..资瓷 区间第K极值查询 似乎不过似乎划分树的效率更优于它,但是如果主席树套树状数组后,可以处理动态的第K极值.即资瓷插入删除,划分树则不同- 那么原理也比较易懂: 建造一棵线段树(权值 ...

  3. Online Judge 2014 K-th Number -主席树

    You are working for Macrohard company in data structures department. After failing your previous tas ...

  4. [BZOJ4771]七彩树(主席树)

    https://blog.csdn.net/KsCla/article/details/78249148 用类似经典的链上区间颜色计数问题的做法,这个题可以看成是询问DFS在[L[x],R[x]]中, ...

  5. [学习笔记] 可持久化线段树&主席树

    众所周知,线段树是一个非常好用也好写的数据结构, 因此,我们今天的前置技能:线段树. 然而,可持久化到底是什么东西? 别急,我们一步一步来... step 1 首先,一道简化的模型: 给定一个长度为\ ...

  6. 【数据结构模版】可持久化线段树 && 主席树

    浙江集训Day4,从早8:00懵B到晚21:00,只搞懂了可持久化线段树以及主席树的板子.今天只能记个大概,以后详细完善讲解. 可持久化线段树指的是一种基于线段树的可回溯历史状态的数据结构.我们想要保 ...

  7. 【BZOJ3439】Kpm的MC密码 trie树+主席树

    Description 背景 想Kpm当年为了防止别人随便进入他的MC,给他的PC设了各种奇怪的密码和验证问题(不要问我他是怎么设的...),于是乎,他现在理所当然地忘记了密码,只能来解答那些神奇的身 ...

  8. HDU5790 Prefix 字典树+主席树

    分析:这个题和spoj的d_query是一个题,那个是求一段区间里有多少个不同的数字,这里是统计有多少个不同的前缀 用字典树进行判重,(和查询不同的数字一样)对于每个不同的前缀,只保留它最后一次出现的 ...

  9. bzoj 3545&&3551: [ONTAK2010]Peaks &&加强版 平衡树&&并查集合并树&&主席树

    3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 635  Solved: 177[Submit][Stat ...

随机推荐

  1. python中的格式化字符

    python中的格式化字符在python中我们会遇到一个问题,问题是如何输出格式化的字符串.我们经常会输出类似'亲爱的xxx你好!你xx月的话费是xx,余额是xx'之类的字符串,而xxx的内容都是根据 ...

  2. IP地址 子网掩码 默认网关和DNS服务器的关系

    在过去,男人是需要能够上房揭瓦的,是要能够修水管的.现在的男人是需要会装系统的,会设置路由器的.世界变化太快! 废话不多说,本文来讨论一下电脑上最为常见的几个网络参数:IP地址.子网掩码.默认网关和D ...

  3. java中properties的使用实例

    package com.ywx.io; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputSt ...

  4. COGS 886. [USACO 4.2] 完美的牛栏

    ★★☆   输入文件:stall4.in   输出文件:stall4.out   简单对比时间限制:1 s   内存限制:128 MB USACO/stall4(译by Felicia Crazy) ...

  5. Eclipse添加默认的JRE

    打开eclipse,依次点击如下选项Window->Preferences-> Java -> Installed JREs.步骤见下图.   选中Installed JREs选项出 ...

  6. Android(java)学习笔记176: 远程服务的应用场景(移动支付案例)

    一. 移动支付:       用户需要在移动终端提交账号.密码以及金额等数据 到 远端服务器.然后远端服务器匹配这些信息,进行逻辑判断,进而完成交易,返回交易成功或失败的信息给移动终端.用户提交账号. ...

  7. laravel composer 扩展包开发(超详细)

    laravel composer 扩展包开发(超详细) 置顶 2018年02月05日 11:09:16 Simael__Aex 阅读数:10396    版权声明:转载请注明出处:http://blo ...

  8. Hydraulic Motor Manufacturers - What Is A Cycloidal Hydraulic Motor?

    The     Hydraulic Motor manufacturers    stated that the cycloidal hydraulic motor is fixedly connec ...

  9. No-7.系统信息相关命令

    系统信息相关命令 本节内容主要是为了方便通过远程终端维护服务器时,查看服务器上当前 系统日期和时间 / 磁盘空间占用情况 / 程序执行情况 本小结学习的终端命令基本都是查询命令,通过这些命令对系统资源 ...

  10. luogu P1821 Silver Cow Party

    题目描述 One cow from each of N farms (1 ≤ N ≤ 1000) conveniently numbered 1..N is going to attend the b ...