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

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

2013-11-15 17:17 411 查看
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_pair
typedef 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_pair

typedef 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: