hdu 3726 Graph and Queries (Treap应用,名次树)

名次树还是比较容易理解的。这道题经典主要在于可以用并查集来维护连通的点,并且使用离线算法,倒过来处理,把分开变成了合并!!

PS: 虽然这道题不存在这个问题。但有时,可能remove不存在的值,如果不先find就可能会爆栈。。(因为一直找不到->一直找)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <set>
#include <limits>
using namespace std;

#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define REP(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define UREP(i, s, t) for(int (i)=(s);(i)>=(t);--(i))
#define REPOK(i, s, t, o) for(int (i)=(s);(i)<=(t) && (o);++(i))

#define MAXN 100
#define MAXM 10000
#define MOD 10000007

#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398

typedef long long LL;

const double maxdouble = numeric_limits<double>::max();
const double eps = 1e-10;
const int INF = 0x7FFFFFFF;

//Treap
// 每个节点有两个属性:rank和value
// 按照rank 这是一个堆
// 按照value 是一颗排序二叉树
//节点定义
typedef struct Node {
    Node *ch[2];
    int r;  // rank
    int v;  // value
    int s;  // size 名次树中子树结点个数

    int cmp(int x) const {
        if (x == v) return -1;
        return x < v ? 0 : 1;
    }
    void maintain() {
        s = 1;
        if (ch[0] != NULL) s += ch[0]->s;
        if (ch[1] != NULL) s += ch[1]->s;
    }
}TreapNode;
class Treap {
public:
    void insert(TreapNode* &o, int x) {
        if (o == NULL) {
            //o = new TreapNode();
            //o->ch[0] = o->ch[1] = NULL;
            //o->v = x;
            //o->r = rand();
            //o->s = 1;
            make_node(o, x);
        } else {
            //int d = o->cmp(x);
            int d = o->v > x ? 0 : 1; // 名次数中的v可能重复
            insert(o->ch[d], x);
            if (o->ch[d]->r > o->r)
                rotate(o, d^1);
        }
        o->maintain();
    }
    // 两棵子树:先把优先级较高的旋转到根
    // 然后在另一棵子树中递归删除x
    void remove(TreapNode* &o, int x) {
        int d = o->cmp(x);
        if (d == -1) {
            TreapNode* u = o;
            if (o->ch[0] == NULL) {
                o = o->ch[1];
                delete u;
            } else if (o->ch[1] == NULL) {
                o = o->ch[0];
                delete u;
            } else {
                if (o->ch[0]->r > o->ch[1]->r) {
                    d = 1;
                } else {
                    d = 0;
                }
                rotate(o, d);
                remove(o->ch[d], x);
            }
        } else {
            remove(o->ch[d], x);
        }
        if(o != NULL) o->maintain();
    }
    // 求第k大的值 0表示不存在
    int kth(TreapNode* o, int k) {
        if (o == NULL || k <= 0 || k > o->s) return 0;
        int s = o->ch[1] == NULL ? 0 : o->ch[1]->s;
        if (k == s+1) return o->v;
        else if (k <= s) return kth(o->ch[1], k);
        else return kth(o->ch[0], k-s-1);
    }
    void make_node(TreapNode* &o, int x) {
        o = new TreapNode();
        o->ch[0] = o->ch[1] = NULL;
        o->r = rand();
        o->s = 1;
        o->v = x;
    }
    void destroy(TreapNode* &o) {
        if (o->ch[0] != NULL) destroy(o->ch[0]);
        if (o->ch[1] != NULL) destroy(o->ch[1]);
        delete o;
        o = NULL;
    }

private:
        // 旋转操作:d=0左转 d=1右转
    void rotate(TreapNode* &o, int d) {
        TreapNode* k = o->ch[d^1];o->ch[d^1] = k->ch[d];k->ch[d] = o;
        // o成为k的子树 而k的另一个子树没发生变化
        // 所以先维护o 在维护k
        o->maintain();
        k->maintain();
        o = k;
    }
};

struct Command{
    char c;
    int param1;
    int param2;
};

const int maxn = 20000;
const int maxm = 60000;
const int maxc = 600000;

int n, m;
Command cmds[maxc+5];
int from[maxm + 5];
int to[maxm + 5];
bool removed[maxm + 5];
int w[maxn + 5];
//Treap
Treap treap;
TreapNode* root[maxn + 5];
// Union-find
int pa[maxn + 1];
int findset(int x) {
    return pa[x] == x ? x : pa[x] = findset(pa[x]);
}

void mergeto(TreapNode* &src, TreapNode* &dst) {
    if (src->ch[0] != NULL) mergeto(src->ch[0], dst);
    if (src->ch[1] != NULL) mergeto(src->ch[1], dst);
    treap.insert(dst, src->v);
    delete src;
    src = NULL;
}

int main() {
    //freopen("input.in", "r", stdin);
    char ch;
    int cases = 0, x, y;
    while(scanf("%d%d",&n,&m) == 2 && (n || m)) {
        memset(removed, false, sizeof(removed));
        REP(i, 1, n) scanf("%d", &w[i]);
        REP(i, 1, m) scanf("%d%d",&from[i], &to[i]);
        int cnt = 0;
        for(;;) {
            for(;;) {
                scanf("%c",&ch);
                if (isalpha(ch))
                    break;
            }
            cmds[cnt].c = ch;
            if (ch == 'E') break;
            if (ch == 'D') {
                scanf("%d",&x);
                removed[x] = true;
                cmds[cnt].param1 = x;
            } else if(ch == 'Q') {
                scanf("%d%d",&x, &y);
                cmds[cnt].param1 = x;
                cmds[cnt].param2 = y;
            } else {
                scanf("%d%d",&x, &y);
                cmds[cnt].param1 = x;
                cmds[cnt].param2 = w[x];
                w[x] = y;
            }
            ++cnt;
        }

        REP(i, 1, n) treap.make_node(root[i], w[i]);

        REP(i, 1, n) pa[i] = i;
        REP(i, 1, m)
            if (!removed[i]) {
                x = findset(from[i]);
                y = findset(to[i]);
                if (x != y) {
                    if (root[x]->s < root[y]->s) {
                        mergeto(root[x], root[y]);
                        pa[x] = y;
                    } else {
                        mergeto(root[y], root[x]);
                        pa[y] = x;
                    }
                }
            }
        LL sum = 0;
        int query_cnt = 0;
        UREP(i, cnt-1, 0) {
            if (cmds[i].c == 'D') {
                int e = cmds[i].param1;
                int x = findset(from[e]), y = findset(to[e]);
                if (x != y) {
                    if (root[x]->s < root[y]->s) {
                        mergeto(root[x], root[y]);
                        pa[x] = y;
                    } else {
                        mergeto(root[y], root[x]);
                        pa[y] = x;
                    }
                }
            } else if (cmds[i].c == 'C') {
                int x = cmds[i].param1;
                int v = cmds[i].param2;
                int fa = findset(x);
                treap.remove(root[fa], w[x]);
                treap.insert(root[fa], v);
                w[x] = v;
            } else {
                int x = findset(cmds[i].param1);
                int k = cmds[i].param2;
                ++query_cnt;
                sum += treap.kth(root[x], k);
            }
        }
        printf("Case %d: %.6f\n",++cases, sum/(double)query_cnt);

        REP(i, 1, n)
            if (root[i] != NULL) treap.destroy(root[i]);
    }

    return 0;
}
使用真实指针null代替NULL的版本
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <set>
#include <limits>
using namespace std;

#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define REP(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define UREP(i, s, t) for(int (i)=(s);(i)>=(t);--(i))
#define REPOK(i, s, t, o) for(int (i)=(s);(i)<=(t) && (o);++(i))

#define MAXN 100
#define MAXM 10000
#define MOD 10000007

#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398

typedef long long LL;

const double maxdouble = numeric_limits<double>::max();
const double eps = 1e-10;
const int INF = 0x7FFFFFFF;

//Treap
// 每个节点有两个属性:rank和value
// 按照rank 这是一个堆
// 按照value 是一颗排序二叉树
//节点定义
typedef struct Node {
    Node *ch[2];
    int r;  // rank
    int v;  // value
    int s;  // size 名次树中子树结点个数

    int cmp(int x) const {
        if (x == v) return -1;
        return x < v ? 0 : 1;
    }
    void maintain() {
        s = ch[0]->s + ch[1]->s + 1;
    }
}TreapNode;
class Treap {
public:
    Treap() {
        null = new TreapNode();
        null->ch[0] = null->ch[1] = null;
        null->s = 0;}
    ~Treap(){delete null;}
    void insert(TreapNode* &o, int x) {
        if (o == null) {
            //o = new TreapNode();
            //o->ch[0] = o->ch[1] = null;
            //o->v = x;
            //o->r = rand();
            //o->s = 1;
            make_node(o, x);
        } else {
            //int d = o->cmp(x);
            int d = o->v > x ? 0 : 1; // 名次数中的v可能重复
            insert(o->ch[d], x);
            if (o->ch[d]->r > o->r)
                rotate(o, d^1);
        }
        o->maintain();
    }
    // 两棵子树:先把优先级较高的旋转到根
    // 然后在另一棵子树中递归删除x
    void remove(TreapNode* &o, int x) {
        int d = o->cmp(x);
        if (d == -1) {
            TreapNode* u = o;
            if (o->ch[0] == null) {
                o = o->ch[1];
                delete u;
            } else if (o->ch[1] == null) {
                o = o->ch[0];
                delete u;
            } else {
                if (o->ch[0]->r > o->ch[1]->r) {
                    d = 1;
                } else {
                    d = 0;
                }
                rotate(o, d);
                remove(o->ch[d], x);
            }
        } else {
            remove(o->ch[d], x);
        }
        if(o != null) o->maintain();
    }
    // 求第k大的值 0表示不存在
    int kth(TreapNode* o, int k) {
        if (o == null || k <= 0 || k > o->s) return 0;
        int s = o->ch[1] == null ? 0 : o->ch[1]->s;
        if (k == s+1) return o->v;
        else if (k <= s) return kth(o->ch[1], k);
        else return kth(o->ch[0], k-s-1);
    }
    void make_node(TreapNode* &o, int x) {
        o = new TreapNode();
        o->ch[0] = o->ch[1] = null;
        o->r = rand();
        o->s = 1;
        o->v = x;
    }
    void destroy(TreapNode* &o) {
        if (o == null) return;
        if (o->ch[0] != null) destroy(o->ch[0]);
        if (o->ch[1] != null) destroy(o->ch[1]);
        delete o;
        o = null;
    }

    TreapNode* null;
private:
        // 旋转操作:d=0左转 d=1右转
    void rotate(TreapNode* &o, int d) {
        TreapNode* k = o->ch[d^1];o->ch[d^1] = k->ch[d];k->ch[d] = o;
        // o成为k的子树 而k的另一个子树没发生变化
        // 所以先维护o 在维护k
        o->maintain();
        k->maintain();
        o = k;
    }
};

struct Command{
    char c;
    int param1;
    int param2;
};

const int maxn = 20000;
const int maxm = 60000;
const int maxc = 600000;

int n, m;
Command cmds[maxc+5];
int from[maxm + 5];
int to[maxm + 5];
bool removed[maxm + 5];
int w[maxn + 5];
//Treap
Treap treap;
TreapNode* root[maxn + 5];
// Union-find
int pa[maxn + 1];
int findset(int x) {
    return pa[x] == x ? x : pa[x] = findset(pa[x]);
}

void mergeto(TreapNode* &src, TreapNode* &dst) {
    if (src->ch[0] != treap.null) mergeto(src->ch[0], dst);
    if (src->ch[1] != treap.null) mergeto(src->ch[1], dst);
    treap.insert(dst, src->v);
    delete src;
    src = treap.null;
}

int main() {
    freopen("input.in", "r", stdin);

    char ch;
    int cases = 0, x, y;
    while(scanf("%d%d",&n,&m) == 2 && (n || m)) {
        memset(removed, false, sizeof(removed));
        REP(i, 1, n) scanf("%d", &w[i]);
        REP(i, 1, m) scanf("%d%d",&from[i], &to[i]);
        int cnt = 0;
        for(;;) {
            for(;;) {
                scanf("%c",&ch);
                if (isalpha(ch))
                    break;
            }
            cmds[cnt].c = ch;
            if (ch == 'E') break;
            if (ch == 'D') {
                scanf("%d",&x);
                removed[x] = true;
                cmds[cnt].param1 = x;
            } else if(ch == 'Q') {
                scanf("%d%d",&x, &y);
                cmds[cnt].param1 = x;
                cmds[cnt].param2 = y;
            } else {
                scanf("%d%d",&x, &y);
                cmds[cnt].param1 = x;
                cmds[cnt].param2 = w[x];
                w[x] = y;
            }
            ++cnt;
        }

        REP(i, 1, n) treap.make_node(root[i], w[i]);

        REP(i, 1, n) pa[i] = i;
        REP(i, 1, m)
            if (!removed[i]) {
                x = findset(from[i]);
                y = findset(to[i]);
                if (x != y) {
                    if (root[x]->s < root[y]->s) {
                        mergeto(root[x], root[y]);
                        pa[x] = y;
                    } else {
                        mergeto(root[y], root[x]);
                        pa[y] = x;
                    }
                }
            }

        LL sum = 0;
        int query_cnt = 0;
        UREP(i, cnt-1, 0) {
            if (cmds[i].c == 'D') {
                int e = cmds[i].param1;
                int x = findset(from[e]), y = findset(to[e]);
                if (x != y) {
                    if (root[x]->s < root[y]->s) {
                        mergeto(root[x], root[y]);
                        pa[x] = y;
                    } else {
                        mergeto(root[y], root[x]);
                        pa[y] = x;
                    }
                }
            } else if (cmds[i].c == 'C') {
                int x = cmds[i].param1;
                int v = cmds[i].param2;
                int fa = findset(x);
                treap.remove(root[fa], w[x]);
                treap.insert(root[fa], v);
                w[x] = v;
            } else {
                int x = findset(cmds[i].param1);
                int k = cmds[i].param2;
                ++query_cnt;
                sum += treap.kth(root[x], k);
            }
        }
        printf("Case %d: %.6f\n",++cases, sum/(double)query_cnt);

        REP(i, 1, n) treap.destroy(root[i]);
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值