您的位置:首页 > 产品设计 > UI/UE

HDU 3726 Graph and Queries 离线处理 treap + 并查集

2017-09-04 16:29 435 查看

题目链接

题意

给定一个图,每个点上有权值。三种操作:

1. 删去某条边;

2. 修改某个点的权值;

3. 询问与某个点连通的所有点中权值第 k 大的值;

最后输出所有询问的平均值。

思路

因为是离线操作,所以考虑 倒着处理,先删去所有要删的边,倒着处理的时候再加回去,用并查集维护。

每一个集合都是一个 Treap,合并的时候把 size 小的树里面的点一个个拆出来往 size 大的里面加(即启发式合并)。

Code

#include <bits/stdc++.h>
#define maxn 60010
#define maxm 60010
#define maxop 500010
using namespace std;
typedef long long LL;
int val[maxn], fa[maxn], sz[maxn], u[maxn], v[maxn], n, m, tot, ne[maxn], ccc;
bool vis[maxn], flag[maxn];
struct Edge {
int to, ne;
Edge(int a = 0, int b = 0) : to(a), ne(b) {}
}edge[maxm * 2];
struct Oper { int t, x, y; Oper(int _t=0, int _a=0, int _b=0) : t(_t), x(_a), y(_b) {}} oper[maxop];
struct node {
node* ch[2];
int sz, key, val;
node() { sz = 0; key = INT_MAX; }
node(int x);
update() { sz = ch[0]->sz+ch[1]->sz+1; }
}*null = new node;
node::node(int x) {
sz = 1, key = rand(), val = x;
ch[0] = ch[1] = null;
}
struct treap {
node* root;
treap() { root = null; }
void rotate(node*& t, bool d) {
node* p = t->ch[d];
t->ch[d] = p->ch[!d];
p->ch[!d] = t;
t->update(), p->update();
t = p;
}
void insert(node*& t, int x) {
if (t == null) {
t = new node(x);
return;
}
bool d = x > t->val;
insert(t->ch[d], x);
if (t->ch[d]->key < t->key) rotate(t, d);
else t->update();
}
void erase(node*& t, int x) {
if (t == null) return;
if (t->val == x) {
bool d = t->ch[1]->key < t->ch[0]->key;
if (t->ch[d] == null) { delete t; t = null; return; }
if (t->ch[!d] == null) { node* p = t->ch[d]; delete t; t = p; return; }
rotate(t, d);
erase(t->ch[!d], x);
t->update();
return;
}
bool d = x > t->val;
erase(t->ch[d], x);
t->update();
}
void replace(int x, int y) {
erase(x); insert(y);
}
int calckth(int k) {
if (k < 0 || k > root->sz) return 0;
k = root->sz-k+1;
bool d;
for (node* t = root; t != null; t = t->ch[d]) {
int cnt = t->ch[0]->sz;
if (k == cnt+1) return t->val;
else if (k <= cnt) d = 0;
else d = 1, k -= (cnt+1);
}
}
void mergeto(node*& t, treap* tr) {
if (t->ch[0] != null) mergeto(t->ch[0], tr);
if (t->ch[1] != null) mergeto(t->ch[1], tr);
tr->insert(t->val);
delete t; t = null;
}
void mergeto(treap* T) { mergeto(root, T); }
void erase(int x) { erase(root, x); }
void insert(int x) { insert(root, x); }
int size() { return root->sz; }
}** Treap = new treap *[maxn];
void addEdge(int u, int v) {
edge[tot] = Edge(v, ne[u]);
ne[u] = tot++;
}
void dfs(int u, int f) {
vis[u] = true, fa[u] = f;
for (int i = ne[u]; ~i; i = edge[i].ne) {
int v = edge[i].to;
if (vis[v]) continue;
dfs(v, f);
}
}
int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
void unionn(int x, int y) {
x = find(x), y = find(y);
if (x == y) return;
if (sz[x] > sz[y]) swap(x, y);
fa[x] = y; sz[y] += sz[x];
Treap[x]->mergeto(Treap[y]);
}
int kas;
void work() {
tot = 0;
memset(ne, -1, sizeof(ne));
memset(sz, 0, sizeof(sz));
memset(flag, 0, sizeof(flag));
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; ++i) scanf("%d", &val[i]);
for (int i = 1; i <= m; ++i) {
scanf("%d%d", &u[i], &v[i]);
}
int num = 0; char ch;
while (scanf("\n%c", &ch) && ch != 'E') {
++num;
int x, y, p, w;
if (ch == 'D') {
scanf("%d", &x);
flag[x] = true;
oper[num] = Oper(0, x);
}
else if (ch == 'Q') {
scanf("%d%d", &x, &y);
oper[num] = Oper(1, x, y);
}
else if (ch == 'C') {
scanf("%d%d", &p, &w);
oper[num] = Oper(2, p, val[p]);
val[p] = w;
}
}
for (int i = 1; i <= m; ++i) {
if (!flag[i]) {
addEdge(u[i], v[i]); addEdge(v[i], u[i]);
}
}
for (int i = 1; i <= n; ++i) if (!vis[i]) dfs(i, i);
for (int i = 1; i <= n; ++i) {
Treap[i] = new treap;
++sz[fa[i]];
Treap[fa[i]]->insert(val[i]);
}
LL ans = 0, cnt = 0;
for (int i = num; i > 0; --i) {
if (oper[i].t == 0) unionn(u[oper[i].x], v[oper[i].x]);
else if (oper[i].t == 1) {
ans += (LL)Treap[find(oper[i].x)]->calckth(oper[i].y), ++cnt;
}
else {
Treap[find(oper[i].x)]->replace(val[oper[i].x], oper[i].y);
val[oper[i].x] = oper[i].y;
}
}
printf("Case %d: %.6f\n", ++kas, 1.0 * ans / cnt);
}
int main() {
while (scanf("%d%d", &n, &m) != EOF && n + m) work();
return 0;
}


若干bug…。

delete t;
后忘了写
t = null;


erase 掉一个节点后忘了
return;


vis 数组忘了初始化

treap忘了写初始化部分
root = null;


并查集忘了初始化 sz=1

就是最后一个错误,导致一直TLE,教训惨痛。

花了一个小时写,三个半小时对付各种错误…。

另:学习到了动态创建结构体指针数组(?)的方式

treap** Treap = new treap*[maxn];


参考:没有躲过的坑–new一个指针数组、以及创建动态二维数组 ——博览群书1989
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: