Tunnel Warfare (区间合并)

来源:互联网 发布:retrofit 传json 编辑:程序博客网 时间:2024/05/01 16:59
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 9D 3D 6D 5Q 4Q 5RQ 4RQ 4
Sample Output
1024

这就是传说中的区间合并,感觉不到区间合并,只是一种找区间的感觉,还是一个人有一个人的管辖范围。

#include <iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<stack>#define INF 0x3f3f3f3f#define lson(x) (x<<1)#define rson(x) (x<<1|1)#define ml(x,y) ((x+y)>>1)#define lowbit(x) (x&(-x))using namespace std;typedef long long ll;const int maxn=5e4+10;/*这道题给我的感觉就是,树还是一样的建造。但是我们存储了三个值ls ,ms,rs;分别代表什么意思呢左儿子管辖范围内从最左面第一个没有被炸的点 开始的连续长度值;右儿子管辖范围内从最右面第一个没有被炸的点 开始的连续长度值;ms什么意思呢,就是说当爹的管辖范围内最长的连续线段长度,感觉主要是为了方便判断,是不是满树,空树;就是说除了左右儿子分的这么清楚的,是不是还有一段可以横跨爹给画的界限的线段诺,就是tree[lson(nid)].rs+tree[rson(nid)].ls,那他们的目的是什么呢,主要就是合并的问题,可以直接判断合并到什么程度。*/int n;struct node{    int l,r;    int ls,ms,rs;}tree[maxn*4];void build(int st,int ed,int nid){    tree[nid].l=st;    tree[nid].r=ed;    tree[nid].ls=tree[nid].ms=tree[nid].rs=ed-st+1;//先都是满树    if(st==ed)        return;    int mid=ml(st,ed);    build(st,mid,lson(nid));    build(mid+1,ed,rson(nid));}void update(int nid,int num,int val){    if(tree[nid].l==tree[nid].r)//说明这是单点,首先明白我们是点更新,一定是更新到点的,只不过回去的时候做了个标记    {        tree[nid].ls=tree[nid].ms=tree[nid].rs=val;//找到单点,对其更新,该连的连,该断的断        return;    }    int mid=ml(tree[nid].l,tree[nid].r);    if(num<=mid)        update(lson(nid),num,val);//这是去找人(点)    else        update(rson(nid),num,val);/*我们是先往下找,因为我们不知道下面是什么情况,只有他反馈回来,我们才知道下面子孙的情况*/    if(tree[lson(nid)].ms==tree[lson(nid)].r-tree[lson(nid)].l+1)//左子树满了,也就是说,左边儿子的管辖区域内都是连通的        tree[nid].ls=tree[lson(nid)].ms+tree[rson(nid)].ls;//这样的话,爹的左连续区间应该是 左+右儿子的区间内 和左儿子相连的    else        tree[nid].ls=tree[lson(nid)].ls;//要不然的话,当爹的左连续区间只能是,左儿子的左连续区间,也就是说当爹的管辖范围内,最左面那条线段了    if(tree[rson(nid)].ms==tree[rson(nid)].r-tree[rson(nid)].l+1)//同理        tree[nid].rs=tree[rson(nid)].ms+tree[lson(nid)].rs;    else        tree[nid].rs=tree[rson(nid)].rs;    tree[nid].ms=max(max(tree[lson(nid)].ms,tree[rson(nid)].ms),tree[lson(nid)].rs+tree[rson(nid)].ls);}int query(int nid,int num){    if(tree[nid].l==tree[nid].r||tree[nid].ms==0||tree[nid].ms==tree[nid].r-tree[nid].l+1)//到了叶子,空树,满树        return tree[nid].ms;//可以直接返回了,因为他问的是区间,而你那个点正好就在这个区间内,然而这三种情况就可以直接判断了    int mid=ml(tree[nid].l,tree[nid].r);    if(num<=mid)    {        if(num<tree[lson(nid)].r-tree[lson(nid)].rs+1)//说明不在左儿子管辖区间内的最右右连续的线段上            return query(lson(nid),num);//那我们就得继续往下查找        else//否则,就说明它在左儿子和右儿子的范围内的那条线段上            return tree[lson(nid)].rs+tree[rson(nid)].ls;//我们就返回这个骑着的区间值    }    else//同理    {        if(num>tree[rson(nid)].l+tree[rson(nid)].ls-1)            return query(rson(nid),num);        else            return tree[lson(nid)].rs+tree[rson(nid)].ls;    }}int main(){   int m;   while(~scanf("%d %d",&n,&m))   {        stack<int> stk;        build(1,n,1);        while(m--)        {            char str;            int temp;            scanf(" %c",&str);            if(str=='D')            {                scanf("%d",&temp);                stk.push(temp);                update(1,temp,0);//从根进去,temp,损伤            }            else  if(str=='Q')            {                scanf("%d",&temp);                printf("%d\n",query(1,temp));//从根进去,查询temp            }            else            {                temp=stk.top();                stk.pop();                update(1,temp,1);//从根进去,temp,修复            }        }     }      return 0;}


原创粉丝点击