线段树--区间合并hdu--1540

来源:互联网 发布:linux mkdir函数 编辑:程序博客网 时间:2024/05/18 16:55

Tunnel Warfare

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


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 9D 3D 6D 5Q 4Q 5RQ 4RQ 4
 

Sample Output
1024

线段树本就擅长于处理区间问题,这题思考很久之后,我想到了做法,最开始整个区间是连续的,当破坏了一个村庄之后,当前区间的从左数和从右数的连续区间要更新,L数组用来存当前区间从左数最长区间,R数组用来存当前区间从右到左最长连续区间,S数组是当前区间最大连续区间,lc和rc是端点的区间。而这道题是单点更新,不需要标记,只要往上更新就行了

#include <iostream>#include <stdio.h>#include <string.h>#define siz 50005#define lson(x) ((x)<<1)#define rson(x) (((x)<<1)|1)using namespace std;int sets[siz<<2],lc[siz<<2],rc[siz<<2];int L[siz<<2],R[siz<<2],S[siz<<2];int n,m;int sta[siz];int length(int root){    return rc[root]-lc[root]+1;}void maintain(int root,int v){    L[root]=R[root]=S[root]=(v?length(root):0);///当前状态当前区间更新为有空房间和无空房间}void pushup(int root){    S[root]=max(max(S[lson(root)],S[rson(root)]),R[lson(root)]+L[rson(root)]);    L[root]=L[lson(root)]+(L[lson(root)]==length(lson(root))?L[rson(root)]:0);    ///如果左儿子全是连续区间,则当前区间右儿子从左数的连续区间是从左边数的连续区间的一部分    R[root]=R[rson(root)]+(R[rson(root)]==length(rson(root))?R[lson(root)]:0);    ///同理}void build(int root,int l,int r){    lc[root]=l;    rc[root]=r;    if(l==r){        maintain(root,1);///建树,1代表整个区间连续        return ;    }    int mid=(lc[root]+rc[root])>>1;    build(lson(root),l,mid);    build(rson(root),mid+1,r);    pushup(root);}void modify(int u,int k,int v){///类似于普通线段树的单点更新    //cout<<u<<" "<<k<<"^^^"<<lc[u]<<endl;    if(lc[u]==rc[u]&&lc[u]==k){        maintain(u,v);        return ;    }    int mid=(lc[u]+rc[u])>>1;    //cout<<mid<<" "<<lc[u]<<" "<<rc[u]<<endl;    if(k<=mid) modify(lson(u),k,v);    else modify(rson(u),k,v);    pushup(u);}int query(int rt,int k){    if(lc[rt]==rc[rt]&&lc[rt]==k){        return S[rt];    }    int mid=(lc[rt]+rc[rt])>>1;    if(k<=mid){        if(mid-R[lson(rt)]+1<=k){///最左边比k小,说明k在从右数连续区间内            return R[lson(rt)]+L[rson(rt)];///加上左边的区间        }else{            return query(lson(rt),k);        }    }else{        if(mid+1+L[rson(rt)]-1>=k){///同理            return L[rson(rt)]+R[lson(rt)];        }else{            return query(rson(rt),k);        }    }}int main(){    while(~scanf("%d%d",&n,&m)){    build(1,1,n);    int ind=0;    while(m--){        //getchar();        char c[2];        int v;        scanf("%s",c);        if(c[0]=='D'){            scanf("%d",&v);            sta[ind++]=v;            modify(1,v,0);///村庄被销毁,断点        }        else if(c[0]=='Q'){                scanf("%d",&v);            int ans=query(1,v);            printf("%d\n",ans);        }        else{            if(ind>0){                v=sta[--ind];                modify(1,v,1);///1修复村庄            }        }       // cout<<1<<endl;    }    }    return 0;}



0 0