hdu1540&poj2892Tunnel Warfare(线段树单点更新)

来源:互联网 发布:交通渠化与组织优化 编辑:程序博客网 时间:2024/06/15 05:33

->题目请戳这 和这->

题目大意,给n个点表示n个村庄,一开始都是相连的,现在有3种操作:Q x,查询第与第x个村庄相连的村庄个数;D x,摧毁掉第x个村庄;R  恢复刚摧毁的村庄。

题目分析:每个点用2个状态表示,0表示被摧毁,1表示存在,因为有恢复操作,并且每次恢复上一个被摧毁的村庄,所以用一个栈存储所有被摧毁的村庄,每次R操作恢复栈顶村庄。这题关键是查询操作,如果查询的村庄x不存在,则没有村庄与之相连通,如果存在x村庄,那么从x往2边找连续的存在的村庄。如何找这个连续的存在的村庄,这里提供2种方法:

1。自顶向下找,如果找到左边第一个不存在的村庄,找到右边第一个不存在的村庄,相减即可。

2。自底向上找,我们建立线段树的时候把每个叶子节点即每个村庄的位置找到,然后分别从x-1和x+1的位置往两边找,也是找到第一个不存在的村庄为止。

本来比较看好第二种方法,实际提交了一下,第一种效率貌似高一点。

详情请见代码:

自顶向下:

#include <iostream>#include<cstdio>#include<cstring>using namespace std;const int N = 50005;int stack[N],top;int n,m;int tree[N<<2];char op[3];int leaf[N];void build(int num,int s,int e){    if(s == e)    {        tree[num] = 1;        leaf[s] = num;        return;    }    int mid = (s + e)>>1;    build(num<<1,s,mid);    build(num<<1|1,mid + 1,e);    tree[num] = tree[num<<1] + tree[num<<1|1];}void insert(int num,int s,int e,int pos,int val){    if(s == e)    {        tree[num] = val;        return;    }    int mid = (s + e)>>1;    if(pos <= mid)        insert(num<<1,s,mid,pos,val);    else        insert(num<<1|1,mid + 1,e,pos,val);    if(tree[num<<1] == mid - s + 1 && tree[num<<1|1] == e - mid)        tree[num] = e - s + 1;    else        tree[num] = 0;}int query(int num,int s,int e,int pos,int dir){    if(pos > n || pos < 1)        return pos;    if(tree[num] == e - s + 1)    {        if(dir)//->            return query(1,1,n,e + 1,dir);//重新从e+1开始往右找        else            return query(1,1,n,s - 1,dir);    }    if(s == e)        return s;    int mid = (s + e)>>1;    if(pos <= mid)        return query(num<<1,s,mid,pos,dir);    else        return query(num<<1|1,mid + 1,e,pos,dir);}void print(int num,int s,int e){    for(int i = 1;i <= n;i ++)        printf("%d ",tree[leaf[i]]);}int main(){    int x;    int cnt;    while(scanf("%d%d",&n,&m) != EOF)    {        build(1,1,n);        top = 0;        while(m --)        {            scanf("%s",op);            if(op[0] == 'R')            {                insert(1,1,n,stack[--top],1);            }            else            {                scanf("%d",&x);                if(op[0] == 'D')                {                    insert(1,1,n,x,0);                    stack[top ++] = x;                }                else                {                    int ans = tree[leaf[x]];                    if(ans == 0)                        printf("0\n");                    else                    {                        ans = 1;                        if(x < n)                        {                            cnt = query(1,1,n,x + 1,1);//右                            ans += (cnt - x - 1);                        }                        //printf("cnt:%d\n",cnt);                        if(x > 1)                        {                            cnt = query(1,1,n,x - 1,0);//左                            ans += (x - cnt - 1);                        }                        //printf("cnt:%d\n",cnt);                        printf("%d\n",ans);                    }                }            }        }    }    return 0;}//hdu546MS1008K//poj1036K266MS
自底向上找:

#include <iostream>#include<cstdio>#include<cstring>using namespace std;const int N = 50005;int stack[N],top;int n,m;struct node{    int l,r,len;}tree[N<<2];char op[3];int leaf[N];void build(int num,int s,int e){    if(s == e)    {        tree[num].len = 1;        tree[num].l = tree[num].r = s;        leaf[s] = num;        return;    }    int mid = (s + e)>>1;    build(num<<1,s,mid);    build(num<<1|1,mid + 1,e);    tree[num].len = tree[num<<1].len + tree[num<<1|1].len;    tree[num].l = s;    tree[num].r = e;}void insert(int num,int pos,int val){    if(tree[num].l == tree[num].r)    {        tree[num].len = val;        return;    }    int mid = (tree[num].l + tree[num].r)>>1;    if(pos <= mid)        insert(num<<1,pos,val);    else        insert(num<<1|1,pos,val);    if(tree[num<<1].len == mid - tree[num].l + 1 && tree[num<<1|1].len == tree[num].r - mid)        tree[num].len = tree[num].r - tree[num].l + 1;    else        tree[num].len = 0;}void print(){    int i;    for(i = 1;i <= n;i ++)        printf("%d ",tree[leaf[i]].len);    putchar(10);}int main(){    int x;    int cnt;    while(scanf("%d%d",&n,&m) != EOF)    {        build(1,1,n);        top = 0;        while(m --)        {            scanf("%s",op);            if(op[0] == 'R')            {                insert(1,stack[--top],1);            }            else            {                scanf("%d",&x);                if(op[0] == 'D')                {                    insert(1,x,0);                    stack[top ++] = x;                }                else                {                    int ans = tree[leaf[x]].len;                    if(ans == 0)                        printf("0\n");                    else                    {                        int tl,tr;                        tl = x - 1;//记录x左边第一个断点                        tr = x + 1;//记录x右边第一个断点                        int tmp;                        while(tl >= 1 && tree[leaf[tl]].len == 1)                        {                            tmp = leaf[tl];                            if(tmp & 1)//在右子树上,往根找就是往左找                            {                                while(tree[tmp].len == tree[tmp].r - tree[tmp].l + 1 && tmp > 1)                                {                                    tmp /= 2;                                    if(!(tmp & 1))//到了左子树上,找到头了                                    {                                        break;                                    }                                }                                if(tree[tmp].len == tree[tmp].r - tree[tmp].l + 1)//加上这句优化后hdu515MS2032K                                    tl = tree[tmp].l - 1;//poj2068K282MS                                else                                    tl = tree[tmp<<1|1].l - 1;                            }                            else                                tl --;                        }                        while(tr <= n && tree[leaf[tr]].len == 1)                        {                            tmp = leaf[tr];                            if(tmp & 1)                                tr ++;                            else                            {                                while(tree[tmp].len == tree[tmp].r - tree[tmp].l + 1 && tmp > 1)                                {                                    tmp /= 2;                                    if(tmp & 1)//找到了右子树上面,找到最右边了                                        break;                                }                                if(tree[tmp].len == tree[tmp].r - tree[tmp].l + 1)                                    tr = tree[tmp].r + 1;                                else                                    tr = tree[tmp<<1].r + 1;                            }                        }                        //printf("tl:%d  tr:%d\n",tl,tr);                        ans = tr - tl - 1;                        printf("%d\n",ans);                    }                }            }            //print(1,1,n);            //putchar(10);        }    }    return 0;}//hdu1031MS2032K//poj2068K391MS



原创粉丝点击