正文

线段树的应用PKU29852008-08-21 13:00:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/lqf110/37755.html

分享到:

///////////////////////////////////////////作品名称:并查集及线段树应用//作者姓名:满天飞//作品时间:2008-8-18//最后修改:2008-8-18//Q Q 号码:280282813//版权所有,翻版必究//////////////////////////////////////////写得要死终于过了#include<iostream>using namespace std;typedef struct{    int lbound;   //左界    int rbound;   //右界    int left;   //左子树    int right;   //右子树    int ct;    //覆盖次数}TreeNode;class SegmentTree{    private:        int nodenum;        TreeNode* tree;    public:        SegmentTree(int);        virtual ~SegmentTree(){delete[]tree;} //构建树        void build(int, int); //插入一个数        void insert(int); //删除一个数        void erase(int); //查询第i大的数        int search(int);};SegmentTree::SegmentTree(int a){    tree = new TreeNode[2*a+10];    memset(tree, 0, sizeof(TreeNode)*(2*a+10));    nodenum = 0;    build(a, 1);  }//采用先序从大到小递归构建void SegmentTree::build(int a, int b){    nodenum++;    int v;    v = nodenum;    tree[v].lbound = a;    tree[v].rbound = b;    if((a-b)>1){        tree[v].left = nodenum+1;        build(a, (a+b)/2);        tree[v].right = nodenum+1;        build((a+b)/2, b);    }}//插入某个数到叶子结点为止void SegmentTree::insert(int a){    int mid,f;    f = 1;    while((tree[f].lbound-tree[f].rbound) > 1){  //对遍历过的结点依次增加覆盖次数        tree[f].ct++;  //取区间中值        mid = (tree[f].lbound+tree[f].rbound)>>1;  //比中值要大入左子树        if(a > mid)            f = tree[f].left;  //否则进左子树        else f = tree[f].right;    } //叶子结点覆盖次数增加    tree[f].ct++;}//类似插入操作void SegmentTree::erase(int a){    int mid, f;    f = 1;    while((tree[f].lbound-tree[f].rbound) > 1){        tree[f].ct--;        mid = (tree[f].lbound+tree[f].rbound)>>1;        if(a > mid)            f = tree[f].left;        else f = tree[f].right;    }    tree[f].ct--;}//此树是从大到小排列,1是没有插入到树上的int SegmentTree::search(int a){    int f, l, r;    f = 1; //此树的插入的数比所要查询的少则返回1    if(tree[f].ct < a)        return 1;    else{        while((tree[f].lbound-tree[f].rbound) > 1){            l = tree[f].left;            r = tree[f].right;   //查询的第i个数比左子树存在的数的个数要多则进入右子树            if(a > tree[l].ct){    //减去左子树上的个数                a = a-tree[l].ct;                f = r;            }   //进左子树            else f = l;        }    } //返回叶子结点的左边界    return tree[f].lbound;}class Set{    public:        int* ary;        int length; //查找某个数的根结点        int Find(int index); //合并两个数        void Union(int first, int second);        Set(int n);        virtual ~Set(){delete[]ary;}};Set::Set(int n){    int i;    ary = new int[n+10];    length = n;    for(i = 1; i <= n; ++i)        ary[i] = -1;}//将每次查找过的路线上的结点全部都指向根结点int Set::Find(int index){    int i, j, t;    if(index <= 0 || index > length) return -1; //查找index元素的根结点    for(i = index; ary[i] > 0; i = ary[i]); //将这条路线上的所有元素全部指向根结点    for(j = index; j != i; j = t){        t = ary[j];        ary[j] = i;    }    return i;}//树的根结点保存树的元素个数,以负值的形式保存void Set::Union(int f, int s){ //如果第i棵树的元素比第j棵树的元素要多则将j加入到i中    if(ary[f] <= ary[s]){        ary[f] += ary[s];        ary[s] = f;    } //否则将i加入到j中    else{        ary[s] += ary[f];        ary[f] = s;    }}//算法://1.删除合并前的大小.//2.插入合并后的大小.//3.查询即可.int main(int argv, char* argc[]){    int vex, opt, i;    int optflag, f, s;    int fsize, ssize, froot, sroot;    cin>>vex>>opt;    Set set(vex+10);    SegmentTree tree(vex);    for(i = 0; i < opt; ++i)    {        scanf("%d", &optflag);        if(optflag == 0)        {            scanf("%d%d", &f, &s);            froot = set.Find(f);            sroot = set.Find(s);            if(froot != sroot)            {    //得到树的大小                fsize = -set.ary[froot];                ssize = -set.ary[sroot];    //将合并前的树大小删除                if(fsize > 1)                    tree.erase(fsize);                if(ssize > 1)                    tree.erase(ssize);    //合并后的树大小插入                tree.insert(fsize+ssize);    //合并两棵树                set.Union(froot, sroot);            }        }        else        {            scanf("%d", &f);            cout<<tree.search(f)<<endl;        }    }    return 0;}

阅读(4883) | 评论(2)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册