Tunnel Warfare (线段树区间更新)

本文详细介绍了一道经典算法题目“Tunnel Warfare”的解决方案,利用线段树进行区间更新和查询,实现村庄状态的快速修改与相关村庄数量的计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
Tunnel Warfare
HDU - 1540
https://vjudge.net/problem/HDU-1540#author=cqbzguomao
题意:
      D x:第x个村庄被毁。
      Q x:指挥官询问第x个村庄与其直接或间接相关的村庄数量。
      R:最后毁坏的村庄被重建了。
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
思路:
      线段树区间更新
*/
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
#define maxn 501000
struct node{
  int num;
  int ll,rr;
}tree[maxn<<2];
int n,m;
void update(int now,int len){
  if(tree[now<<1].ll==len-(len>>1)) tree[now].ll=tree[now<<1].ll+tree[now<<1|1].ll;
  else tree[now].ll=tree[now<<1].ll;
  if(tree[now<<1|1].rr==len>>1) tree[now].rr=tree[now<<1|1].rr+tree[now<<1].rr;
  else tree[now].rr=tree[now<<1|1].rr;
  tree[now].num=max(max(tree[now<<1].num,tree[now<<1|1].num),tree[now<<1].rr+tree[now<<1|1].ll);
}
void build(int now,int l,int r){
  if(l==r){
    tree[now].num=1;
    tree[now].ll=1;
    tree[now].rr=1;
    return ;
  }
  int mid=(l+r)>>1;
  build(now<<1,l,mid);
  build(now<<1|1,mid+1,r);
  update(now,r-l+1);
}
void change(int now,int l,int r,int x,int c){
  if(l==r){
    tree[now].num=c;
    tree[now].ll=c;
    tree[now].rr=c;
    return ;
  }
  int mid=(l+r)>>1;
  if(x<=mid) change(now<<1,l,mid,x,c);
  else change(now<<1|1,mid+1,r,x,c);
  update(now,r-l+1);
}
int query(int now,int l,int r,int q){
  if(tree[now].num==(r-l+1)||l==r||tree[now].num==0) return tree[now].num;
  int mid=(l+r)>>1;
  if(q<=mid){
    if(q>=mid-tree[now<<1].rr+1) return tree[now<<1].rr+tree[now<<1|1].ll;
    else return query(now<<1,l,mid,q);
  } else {
    if(q<=mid+tree[now<<1|1].ll) return tree[now<<1].rr+tree[now<<1|1].ll;
    else return query(now<<1|1,mid+1,r,q);
  }
}
stack <int> st;
int main(){
  char q[10];
  int c;
  while(~scanf("%d %d", &n, &m)){
    while(!st.empty()) st.pop();
    build(1,1,n);
    while(m--){
      scanf("%s", q);
      if(q[0]=='D'){
        scanf("%d", &c);
        st.push(c);
        change(1,1,n,c,0);
      }else if(q[0]=='R'){
        change(1,1,n,st.top(),1);
        st.pop();
      }else{
        scanf("%d", &c);
        cout<<query(1,1,n,c)<<endl;
      }
    }
  }
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值