hdu 3726 Graph and Queries , 天津 2010, LA 5031,并查集,Treap,离线处理

来源:互联网 发布:知乎 恶魔的奶爸 编辑:程序博客网 时间:2024/05/01 18:36

Treap树入门练习题目,此题主要来练习Treap的操作

此题也是刘汝佳 大白书,Treap的例题

用指针实现的Treap的操作

注意:

1.不要访问NULL

2.cmp函数的使用,相等时返回-1

其它,待补充。。。

另:

为避免错误和是操作的简洁,可使用一个真实的空指针null代替空指针NULL,。。。

关于内存预申请的优化写法,待补充

//#pragma comment(linker, "/STACK:1024000000,1024000000")#include <cstdio>#include <ctime>#include <cstdlib>#include <cstring>#include <queue>#include <string>#include <set>#include <stack>#include <map>#include <cmath>#include <vector>#include <iostream>#include <algorithm>using namespace std;#define FE(i, a, b) for(int i = (a); i <= (b); ++i)#define FD(i, b, a) for(int i = (b); i >= (a); --i)#define REP(i, N) for(int i = 0; i < (N); ++i)#define CLR(a, v) memset(a, v, sizeof(a))#define PB push_back#define MP make_pairtypedef long long LL;const int INF = 0x3f3f3f3f;struct Node {    Node *ch[2];    int r; ///随机优先级    int v; ///值    int s; ///节点总数    Node(int v) : v(v) { ch[0] = ch[1] = NULL; r = rand(); s = 1; }///    bool operator < (const Node &rhs) const {        return r < rhs.r;    }    int cmp(int x) const {        if (x == v) return -1;        return x < v ? 0 : 1;    }    void pushup() {        s = 1;        if (ch[0] != NULL) s += ch[0]->s;        if (ch[1] != NULL) s += ch[1]->s;    }};///不用确保o有孩子节点吗?void rotate(Node* &o, int d) {    Node* k = o->ch[d ^ 1];    o->ch[d ^ 1] = k->ch[d]; k->ch[d] = o;    o->pushup(); k->pushup(); ///先o后k    o = k;}void insert(Node* &o, int x) {    if (o == NULL) o = new Node(x);    else {        int d = (x < o->v ? 0 : 1);///不要用cmp函数,可能有相同节点        insert(o->ch[d], x);        if (o->ch[d] > o) rotate(o, d ^ 1);    }    o->pushup();}void remove(Node* &o, int x) {    int d = o->cmp(x);    if (d == -1) {        Node* u = o;        if (o->ch[0] != NULL && o->ch[1] != NULL) {            int d2 = (o->ch[0] > o->ch[1] ? 1 : 0);            rotate(o, d2); remove(o->ch[d2], x);        } else {            if (o->ch[0] == NULL) o = o->ch[1];            else o = o->ch[0];            delete u; ///!!!        }    }    else remove(o->ch[d], x);    if (o != NULL) o->pushup();}const int maxc = 500000 + 10;const int maxn = 20000 + 10;const int maxm = 60000 + 10;struct Command {    char type;    int x, p;    Command(){}    Command(char type, int x, int p) : type(type), x(x), p(p){}}Q[maxc];int n, m;int weight[maxn];int from[maxm], to[maxm], removed[maxm];///并查集相关int fa[maxn];void init_fa(int n) {    REP(i, n + 1) fa[i] = i;}int findset(int x) {    return fa[x] == x ? x : fa[x] = findset(fa[x]);}/// 名次树相关Node* root[maxn];///查第k大int kth(Node* 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;    if (k <= s) return kth(o->ch[1], k);    else return kth(o->ch[0], k - s - 1);}void mergeto(Node* &src, Node* &dest) {    if (src->ch[0] != NULL) mergeto(src->ch[0], dest);    if (src->ch[1] != NULL) mergeto(src->ch[1], dest);    insert(dest, src->v);///    delete(src); src = NULL;}void removetree(Node* &o) {    if (o->ch[0] != NULL) removetree(o->ch[0]);    if (o->ch[1] != NULL) removetree(o->ch[1]);    delete(o); o = NULL;}///主程序相关void add_edge(int x) {    int u = findset(from[x]), v = findset(to[x]);    if (u != v) {        if (root[u]->s < root[v]->s) {            fa[u] = v;            mergeto(root[u], root[v]);        }        else {            fa[v] = u;            mergeto(root[v], root[u]);        }    }}int Q_cnt;LL Q_tot;void query(int x, int k) {    Q_cnt++;    Q_tot += kth(root[findset(x)], k);}void change_weight(int x, int v){    int u = findset(x);    remove(root[u], weight[x]);    insert(root[u], v);    weight[x] = v;}int nc;void solve(int c) {    Q_tot = Q_cnt = 0;    for (int i = c - 1; i >= 0; i--) {        if (Q[i].type == 'D') add_edge(Q[i].x);        else if (Q[i].type == 'Q') query(Q[i].x, Q[i].p);        else change_weight(Q[i].x, Q[i].p);    }    printf("Case %d: %.6lf\n", nc++, Q_tot / (1.0 * Q_cnt));}int main () {    nc = 1;    while (scanf("%d%d", &n, &m) == 2 && n) {        for (int i = 1; i <= n; i++) scanf("%d", &weight[i]);        for (int i = 1; i <= m; i++) scanf("%d%d", &from[i], &to[i]);        CLR(removed, 0);        int c = 0;        while (1) {            char type;            int x, p = 0, v = 0;            scanf(" %c", &type);            if (type == 'E') break;            scanf("%d", &x);            if (type == 'D') removed[x] = 1;            if (type == 'Q') scanf("%d", &p);            if (type == 'C') {                scanf("%d", &v);                p = weight[x];///                weight[x] = v;            }            Q[c++] = Command(type, x, p);        }        ///最终图        init_fa(n);        for (int i = 1; i <= n; i++) {            if (root[i] != NULL) removetree(root[i]);            root[i] = new Node(weight[i]);        }        for (int i = 1; i <= m; i++) {            if (!removed[i]) add_edge(i);        }        ///反向操作        solve(c);    }    return 0;}

  使用了null的代码:

//#pragma comment(linker, "/STACK:1024000000,1024000000")#include <cstdio>#include <ctime>#include <cstdlib>#include <cstring>#include <queue>#include <string>#include <set>#include <stack>#include <map>#include <cmath>#include <vector>#include <iostream>#include <algorithm>using namespace std;#define FF(i, a, b) for(int i = (a); i < (b); ++i)#define FE(i, a, b) for(int i = (a); i <= (b); ++i)#define FD(i, b, a) for(int i = (b); i >= (a); --i)#define REP(i, N) for(int i = 0; i < (N); ++i)#define CLR(a, v) memset(a, v, sizeof(a))#define PB push_back#define MP make_pairtypedef long long LL;const int INF = 0x3f3f3f3f;const int MAXN = 100010;struct Node{    Node *ch[2];    int r, v, s;    Node(){}    Node(int v, Node *null):v(v){ ch[0] = ch[1] = null; s = 1; r = rand(); }    int cmp(int x)    {        if (v == x) return -1;        return x < v ? 0 : 1;    }    void maintain()    {        s = ch[0]->s + ch[1]->s + 1;    }    bool operator<(const Node& rhs) const    {        return r < rhs.r;    }}*null;void rotate(Node* &rt, int d){    Node* k = rt->ch[d ^ 1]; rt->ch[d ^ 1] = k->ch[d]; k->ch[d] = rt;    rt->maintain(); k->maintain(); rt = k;}void insert(Node* &rt, int x){    if (rt == null) { rt = new Node(x, null); }    else    {        int d = x < rt->v ? 0 : 1;        insert(rt->ch[d], x);        if (rt < rt->ch[d]) rotate(rt, d ^ 1);    }    rt->maintain();}void remove(Node* &rt, int x){    int d = rt->cmp(x);    if (d == -1)    {        Node* u = rt;        if (rt->ch[0] != null && rt->ch[1] != null)        {            int d2 = rt->ch[0] > rt->ch[1] ? 1 : 0;            rotate(rt, d2);            remove(rt->ch[d2], x);        }        else        {            if (rt->ch[0] == null) rt = rt->ch[1];            else rt = rt->ch[0];            delete(u);        }    }    else remove(rt->ch[d], x);    if (rt != null) rt->maintain();}const int maxc = 500000 + 10;const int maxn = 20000 + 10;const int maxm = 60000 + 10;///名次树相关Node *root[maxn];void init_root(){    null = new Node();    null->ch[0] = null->ch[1] = null;    null->r = null->v = null->s = 0;    for (int i= 0; i < maxn; i++) root[i] = null;}int kth(Node *rt, int k){    if (rt == null || k <= 0 || k > rt->s) return 0;//    int ss = rt->ch[1] == null ? 0 : rt->ch[1]->s;///!!!    int ss = rt->ch[1]->s;    if (k == ss + 1) return rt->v;    else if (k < ss + 1) return kth(rt->ch[1], k);    else return kth(rt->ch[0], k - ss - 1);}void mergeto(Node* &src, Node* &dest){    if (src->ch[0] != null) mergeto(src->ch[0], dest);    if (src->ch[1] != null) mergeto(src->ch[1], dest);    insert(dest, src->v);    delete src;    src = null;}void removetree(Node* &rt){    if (rt->ch[0] != null) removetree(rt->ch[0]);    if (rt->ch[1] != null) removetree(rt->ch[1]);    delete rt;    rt = null;}struct Query{    char op;    int x, p;    Query(){}    Query(char op, int x, int p) : op(op), x(x), p(p) {}}Q[maxc];int Q_cnt;long long Q_sum;int cnt;int n, m;int val[maxn];int from[maxm], to[maxm];bool removed[maxm];///并查集相关int fa[maxn];void init_fa(int n){    for (int i = 0; i <= n; i++) fa[i] = i;}int find_set(int x){    return x == fa[x] ? fa[x] : fa[x] = find_set(fa[x]);}///main相关void add_edge(int i){    int x = from[i], y = to[i];    int fax = find_set(x), fay = find_set(y);    if (fax != fay)    {        if (root[fax]->s < root[fay]->s) ///!!!注意        {            fa[fax] = fay;            mergeto(root[fax], root[fay]);        }        else        {            fa[fay] = fax;            mergeto(root[fay], root[fax]);        }    }}void change(int i, int p){    int fai = find_set(i);    remove(root[fai], val[i]);    val[i] = p;    insert(root[fai], val[i]);}void query(int i, int p){    int fai = find_set(i);    Q_cnt++;    Q_sum += kth(root[fai], p);}int main (){    init_root();    int nc = 1;    while (scanf("%d%d", &n, &m) != EOF && n + m)    {        init_fa(n);        CLR(removed, 0);        for (int i = 1; i <= n; i++) scanf("%d", &val[i]);        for (int i = 1; i <= m; i++) scanf("%d%d", &from[i], &to[i]);        char op;        int x, p;        cnt = 0;        while (~scanf(" %c", &op) && op != 'E')        {            scanf("%d", &x);            if (op == 'D') removed[x] = 1;            else if (op == 'Q') scanf("%d", &p);            else if (op == 'C')            {                scanf("%d", &p);                swap(val[x], p);            }            Q[cnt++] =  Query(op, x, p);        }        for (int i = 1; i <= n; i++)        {            if (root[i] != null) removetree(root[i]);            root[i] = new Node(val[i], null);        }        for (int i = 1; i <= m; i++)        {            if (!removed[i]) add_edge(i);        }        Q_cnt = Q_sum = 0;        for (int i = cnt - 1; i >= 0; i--)        {            if (Q[i].op == 'D') add_edge(Q[i].x);            else if (Q[i].op == 'Q') query(Q[i].x, Q[i].p);            else if (Q[i].op == 'C') change(Q[i].x, Q[i].p);        }        printf("Case %d: %.6lf\n", nc++, Q_sum / (double)Q_cnt);    }    return 0;}