HDU1540 Tunnel Warfare

Tunnel Warfare

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3899    Accepted Submission(s): 1462



Problem Description
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

Source
POJ Monthly


这题WA到快哭了。。。。。。
题意:大概就是求最长的连续的序列。。D表示去掉一个点,Q表示查询这个点所在的最长连续序列,R表示恢复最近删除的那个点。
分析:用线段树维护包含左节点的最长连续长度lsum,和包含右节点的最长连续长度rsum,还有最长的长度msum,然后就是线段树的点更新,每插入一个点,如果是删除的话就把这个点对应的叶节点的lsum,rsum,msum变成0就是,然后再pushup更新到所有区间里去。
查询的时候,因为是查询点的操作,向下走的时候要看这个点如果首先在左区间,就要看他是不是在左区间的包含右节点的连续段,如果在可能右区间的也可以和这一段拼起来形成连续,首先在右区间也类似。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN=50010;
struct seg
{
    int l,r;
    int lsum,rsum,msum;
}tree[MAXN*4];
vector<int> q;
void pushup(int k)
{
    int ll=tree[2*k].r-tree[2*k].l+1;
    int rr=tree[2*k+1].r-tree[2*k+1].l+1;
    tree[k].msum=max(tree[2*k].msum,tree[2*k+1].msum);
    tree[k].msum=max(tree[k].msum,tree[2*k].rsum+tree[2*k+1].lsum);
    tree[k].lsum=tree[2*k].lsum;
    if(tree[2*k].lsum==ll)
        tree[k].lsum+=tree[2*k+1].lsum;
    tree[k].rsum=tree[2*k+1].rsum;
    if(tree[2*k+1].rsum==rr)
        tree[k].rsum+=tree[2*k].rsum;
}
void build(int l,int r,int k)
{
    tree[k].l=l;
    tree[k].r=r;
    tree[k].lsum=tree[k].msum=tree[k].rsum=r-l+1;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    build(l,mid,2*k);
    build(mid+1,r,2*k+1);
}
void update(int n,int d,int k)
{
    if(tree[k].l==tree[k].r&&tree[k].l==n)
    {
        if(d==1)
            tree[k].lsum=tree[k].msum=tree[k].rsum=1;
        else
            tree[k].lsum=tree[k].msum=tree[k].rsum=0;
        return;
    }
    int mid=(tree[k].l+tree[k].r)>>1;
    if(n<=mid)
        update(n,d,2*k);
    else
        update(n,d,2*k+1);
    pushup(k);
}
int query(int n,int k)
{
    if(tree[k].msum==0||tree[k].l==tree[k].r||tree[k].msum==tree[k].r-tree[k].l+1)
        return tree[k].msum;
    int mid=(tree[k].l+tree[k].r)>>1;
    if(n<=mid)  //在左区间
    {
        if(n>=tree[2*k].r-tree[2*k].rsum+1) //在左区间的包含右节点的连续段内
            return query(n,2*k)+query(mid+1,2*k+1);
        else
            return query(n,2*k);
    }
    else
    {
        if(n<=tree[2*k+1].l+tree[2*k+1].lsum-1)
            return query(n,2*k+1)+query(mid,2*k);
        else
            return query(n,2*k+1);
    }
}
int main()
{
    int n,m,i,x;
    char s[2];
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d",&n,&m)==2)
    {
        build(1,n,1);
        while(!q.empty())
            q.pop_back();
        while(m--)
        {
            scanf("%s",s);  //这里不能把x这个时候也输进去,因为如果s是R的话就不会输入x的
            if(s[0]=='D')
            {
                scanf("%d",&x);
                q.push_back(x);
                update(x,0,1);
                continue;
            }
            if(s[0]=='Q')
            {
                scanf("%d",&x);
                int ans=query(x,1);
                printf("%d\n",ans);
                continue;
            }
            if(s[0]=='R'&&!q.empty())
            {
                int u=q.back();
                q.pop_back();
                update(u,1,1);
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值