Tunnel Warfare HDU - 1540 单点更新 区间合并 线段树

During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every village was directly connected with two neighboring ones.

Frequently the invaders launched attack on some of the villages and destroyed the parts of tunnels in them. The Eighth Route Army commanders requested the latest connection state of the tunnels and villages. If some villages are severely isolated, restoration of connection must be done immediately!

Input
The first line of the input contains two positive integers n and m (n, m ≤ 50,000) indicating the number of villages and events. Each of the next m lines describes an event.

There are three different events described in different format shown below:

D x: The x-th village was destroyed.

Q x: The Army commands requested the number of villages that x-th village was directly or indirectly connected with including itself.

R: The village destroyed last was rebuilt.
Output
Output the answer to each of the Army commanders’ request in order on a separate line.
Sample Input
7 9
D 3
D 6
D 5
Q 4
Q 5
R
Q 4
R
Q 4
Sample Output
1
0
2
4


类似的题目之前没有做过,想了很久没想出来,看的题解后A的。这道题需要引进从区间左边向右边延展的可行域(ll),从右边向左延展的可行域(rr),区间的最大可行域(data)。

如果我们要查询,那么从最大的区间折半查询,问题是如何确定区间的取舍问题。其实存在着如下关系。

假设我们要查询的点为t。

分别对t进行讨论,如果t在左子树并且在左子树的rr之内,就要查询一下左子树,右子树。如果不在就只是查询左子树。

t在右子树内同理

还有一个问题,就是在需要查询相邻子树的时候查询点如何选取。如果这个条件成立,我们就要去选择相邻子树的端点。为什么?因为只有端点值是最可靠的(自行思考)。

  通过做这道题,还是觉得关系都是从最基础找起。比如更新ll,rr,其实在叶子节点ll,rr的值已经是可以确定的,当叶子节点为1时,ll=rr=data=1,当叶子节点为0时,

ll=rr=data=0。然后就是向上去更新,上边的区间rr是右子树的rr,ll是左子树的ll。当然,子树满的情况分别讨论。

#include<bits/stdc++.h>
using namespace std;
const int M=5e4+10;
struct  aa
{
    int ll,rr,data;
} tree[4*M];
int save[M],stc[M];
void  creat(int now,int l,int r)
{

    tree[now].ll=tree[now].rr=tree[now].data=r-l+1;
    if(l==r)
        return ;
    int mid=(r+l)/2;
    creat(now*2+1,l,mid);
    creat(now*2+2,mid+1,r);
}
void update(int now,int l,int r,int t,int w)
{
    if(l==r)
    {
        tree[now].ll=tree[now].rr=tree[now].data=w;
        return ;
    }
    int mid=(l+r)/2;
    if(t<=mid)
    {
        update(now*2+1,l,mid,t,w);
    }
    else
    {
        update(now*2+2,mid+1,r,t,w);
    }
    tree[now].ll=tree[now*2+1].ll;
    tree[now].rr=tree[now*2+2].rr;
    tree[now].data=max(max(tree[now*2+1].data,tree[now*2+2].data),tree[now*2+1].rr+tree[now*2+2].ll);
    if(tree[now*2+1].ll==mid-l+1)
    {
        tree[now].ll+=tree[now*2+2].ll;
    }
    if(tree[now*2+2].ll==r-mid)
    {
        tree[now].rr+=tree[now*2+1].rr;
    }
}
int query(int now,int l,int r,int t)
{
    if(l==r||tree[now].data==0||tree[now].data==r-l+1)
        return tree[now].data;
    int mid=(l+r)/2;
    if(t<=mid)
    {
        if(t>=mid-tree[now*2+1].rr+1)
        {
            return query(now*2+1,l,mid,t)+query(now*2+2,mid+1,r,mid+1);
        }
        else
        {
            return query(now*2+1,l,mid,t);
        }
    }
    else
    {
        if(t<=mid+tree[now*2+2].ll)
        {
            return query(now*2+1,l,mid,mid)+query(now*2+2,mid+1,r,t);
        }
        else
        {
            return  query(now*2+2,mid+1,r,t);
        }
    }
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int top=0;
        creat(0,0,n-1);
        getchar();
        while(m--)
        {
            char tempchar;
            int tempint;
            scanf("%c",&tempchar);
            getchar();
            if(tempchar=='D')
            {

                scanf("%d",&tempint);
                getchar();
                stc[++top]=tempint;
                update(0,0,n-1,tempint-1,0);
            }
            else if(tempchar=='Q')
            {
                scanf("%d",&tempint);
                getchar();
                printf("%d\n",query(0,0,n-1,tempint-1));
            }
            else
            {
                tempint=stc[top--];
                update(0,0,n-1,tempint-1,1);
            }
        }
    }
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值