zoukankan      html  css  js  c++  java
  • hdu 1540 线段树

    这题的意思是现在有一些村庄成一条直线排列,现在有三个操作,D:摧毁一个指定的村庄,Q:询问与指定村庄相连的村庄个数,

    就是这个村庄向左和向右数村庄数量,遇到尽头或损坏的村庄为止,这个就是与这个村庄相连的村庄数量,当然,如果指定村庄已经被摧毁,则数量为0。R:把最后摧毁的那一个村庄恢复。在这里D操作和R操作都可以看成对线段树的单点修改,只是执行的操作不同,

    最主要的是如何找和指定村庄相连的村庄数量,刚刚做的时候我很纠结,看了别人博客后...  我们可以定义一个max1和一个min1,表示这个区间里的最大值和最小值(max1初始化为-1,min1初始化为无穷大),这样一开始就是没有左右边界,如果某个村庄被摧毁,则把他的max1和min1都变成他的节点值,(自己体会一下下)

    如果我们想找a村庄的的相连村庄数目,惯性思维是想一次性就把左右两个边界求出来,后来才发现我们其实可以用两次区间查询来分别找到a的左边界和右边界,query1(1,a,1)和query2(a,n,1)就是找区间1到a的的最大值和区间a到n的最小值,然后存一下这两个边界,最后相减。

    具体可以看看代码:

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<stack>
    using namespace std;
    #define inf 0x3f3f3f
    struct node{
        int l,r,min1,max1;
    }str[4*50000+5];
    stack<int>s;
    int n,m,k,t,a,b;
    int start,end1;
    char ss[3];
    void build(int l,int r,int k)
    {
        str[k].l=l;
        str[k].r=r;
        str[k].max1=-1;
        str[k].min1=inf;
        if(l==r)
        {
            return;
        }
        int mid=(l+r)/2;
        build(l,mid,k*2);
        build(mid+1,r,k*2+1);
        str[k].max1=max(str[k*2].max1,str[k*2+1].max1);
        str[k].min1=min(str[k*2].min1,str[k*2+1].min1);
    }
    void change_point1(int k)//摧毁a点 
    {
        if(str[k].l==str[k].r&&str[k].l==a)
        {
            str[k].max1=str[k].l;
            str[k].min1=str[k].l;
            return;
        }
        int mid=(str[k].l+str[k].r)/2;
        if(a<=mid)
        change_point1(k*2);
        else
        change_point1(k*2+1);
        str[k].max1=max(str[k*2].max1,str[k*2+1].max1);
        str[k].min1=min(str[k*2].min1,str[k*2+1].min1);
    }
    void change_point2(int k)//恢复a点 
    {
        if(str[k].l==str[k].r&&str[k].l==a)
        {
            str[k].max1=-1;
            str[k].min1=inf;
            return;
        }
        int mid=(str[k].l+str[k].r)/2;
        if(a<=mid)
        change_point2(k*2);
        else
        change_point2(k*2+1);
        str[k].max1=max(str[k*2].max1,str[k*2+1].max1);
        str[k].min1=min(str[k*2].min1,str[k*2+1].min1);
    }
    void query1(int l,int r,int k)//找a点的左边界 
    {
        if(str[k].l>=l&&str[k].r<=r)
        {
            start=max(str[k].max1,start);
            return;
        }
        int mid=(str[k].l+str[k].r)/2;
        if(l<=mid)
        query1(l,r,k*2);
        if(r>mid)
        query1(l,r,k*2+1);
     } 
    void query2(int l,int r,int k)//找a点的右边界 
    {
        if(str[k].l>=l&&str[k].r<=r)
        {
            end1=min(end1,str[k].min1);  
            return;
        }
        int mid=(str[k].l+str[k].r)/2;
        if(l<=mid)
        query2(l,r,k*2);
        if(r>mid)
        query2(l,r,k*2+1);
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            build(1,n,1);
            while(!s.empty())
            s.pop();
            for(int i=0;i<m;i++)
            {
                scanf("%s",ss);
                if(ss[0]=='D')
                {
                    scanf("%d",&a);
                    change_point1(1);
                    s.push(a);
                }
                else if(ss[0]=='Q')
                {
                    scanf("%d",&a);
                    start=-1;
                    end1=inf;
                    query1(1,a,1);
                    query2(a,n,1);
                    if(start==-1)//特判一下 
                    start=0;
                    if(end1==inf)
                    end1=n+1;
                    int ans=end1-start-1;
                    
                    if(start==end1)
                    ans=0;
                    printf("%d
    ",ans);
                }
                else if(ss[0]=='R')
                {
                    if(!s.empty())
                    {
                        a=s.top();
                        change_point2(1);
                        s.pop();
                    }
                }
            }
        }
        return 0;
     } 
  • 相关阅读:
    RESTful API 设计最佳实践
    Linux给目录创建软链接的技巧
    KVM资源划分分配技巧
    SpringBoot无法启动,Process finished with exit code 0
    Shell中EOF内容转义
    TeamViewer运行在Windows Server 2008下连接时错误提示:正在初始化显示参数
    CentOS使用chkconfig增加开机服务提示service xxx does not support chkconfig的问题解决
    Redis哨兵模式主从同步不可以绑定127.0.0.1或者0.0.0.0,不然无法进行主从同步
    Spring Boot项目的Logback配置文件使用yaml格式
    Shell脚本里的双冒号是什么意思
  • 原文地址:https://www.cnblogs.com/6262369sss/p/9147298.html
Copyright © 2011-2022 走看看