• Tunnel Warfare HDU


    题意: 在一条直线上右连续的n个点,现在,给你m个操作,D  x   破坏点 x。Q   x 查询,点x所在的区间的最长的没被破坏的连续的点的个数。

    思路:线段数的区间更新 ,节点维护区间的最长连续的点的个数,其中有两个难点,即PushUp函数,和 query(查询) 函数

    具体操作即作用在注释里面都有写到。(不明白的可以评论,或者私我,有时间一定马上回复,谢谢支持!)

    (query操作参考了kuangbindalao的博客,注释加上了一点我自己的理解,如有错误,欢迎指出)

    #include "iostream"
    #include "stack"
    #include "algorithm"
    using  namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    const  int Max=50005;
    int sum[Max<<2],lsum[Max<<2],rsum[Max<<2];//分别记录总区间,从左端点开始,从右端点开始的最长连续区间
    void build(int l,int r,int rt)
    {
        sum[rt]=lsum[rt]=rsum[rt]=r-l+1;//最初,区间的最长连续区间即本区间的长度
        if(l==r) return;
        int m=(l+r)>>1;
        build(lson);
        build(rson);
    }
    void PushUp(int rt,int ll,int lr)
    {
        lsum[rt]=lsum[rt<<1];
        rsum[rt]=rsum[rt<<1|1];
        if(lsum[rt]==ll) lsum[rt]+=lsum[rt<<1|1];//如果左区间的最长连续区间与左区间等长,说明区间没有被隔开,那么总区间的
        if(rsum[rt]==lr) rsum[rt]+=rsum[rt<<1];//区间还要加上右区间的最长连续区间,对于右区间的来说也是如此
        sum[rt]=max(rsum[rt<<1]+lsum[rt<<1|1],max(sum[rt<<1],sum[rt<<1|1]));//最后,总区间的最长连续区间即为可能的三个区间的最大值
    }
    void update(int c,int x,int l,int r,int rt)
    {
        if(l==r){
            sum[rt]=lsum[rt]=rsum[rt]=c?1:0;//单点更新,如果是删除操作,那么赋值为0,否则为1
            return;
        }
        int m=(l+r)>>1;
        if(x<=m) update(c,x,lson);
        else update(c,x,rson);
        PushUp(rt,m-l+1,r-m);//更新值
    }
    int query(int x,int l,int r,int rt)
    {
        if(l==r||sum[rt]==0||sum[rt]==r-l+1)//如果已经到了叶子节点或者最长连续区间为0或者最长连续区间为区间的长都可以直接返回
            return sum[rt];
        int m=(l+r)>>1;
        if(x<=m){
            if(x>=m-rsum[rt<<1]+1)//因为t<=mid,看左子树,m-rsum[rt<<1]+1代表左子树右边连续区间的左边界值,如果t在左子树的右区间内
            return query(x,lson)+query(m+1,rson);//那么还要加上右边的一段区间
            else//如果不在左子树的右边界区间内,则只需要看左子树
                return query(x,lson);
        }
        else{
            if(x<=m+1+lsum[rt<<1|1]-1)//右子树同理
                return query(x,rson)+query(m,lson);
            else
                return query(x,rson);
        }
    }
    int main()
    {
        ios::sync_with_stdio(false);
        int n,m;
        while(cin>>n>>m){
            stack<int> s;//用一个栈来记录删除的点
            if(!s.empty()) s.pop();
            build(1,n,1);
            char ch;
            int x;
            while(m--){
                cin>>ch;
                if(ch=='D'){
                    cin>>x;
                    s.push(x);
                    update(0,x,1,n,1);
                }
                else if(ch=='R'){
                    if(x>0){
                        x=s.top();
                        s.pop();
                        update(1,x,1,n,1);
                    }
                }
                else{
                    cin>>x;
                    cout<<query(x,1,n,1)<<endl;
                }
            }
        }
        return  0;
    }

  • 相关阅读:
    【F#】 WebSharper框架
    【F#】 入门代码
    【F#】核心数据多线程处理的首选
    【Jetlang】一个高性能的Java线程库
    【项目管理】 并发服务设计的三种架构
    【Go】为什么用go; Golang Erlang 前世今生
    【Go】 http webserver
    Arcane Numbers 1
    给定4根长度的线段,求组成四边形的最大面积
    #410div2D. Mike and distribution
  • 原文地址:https://www.cnblogs.com/Levi-0514/p/9092858.html
Copyright © 2020-2023  润新知