时隔一年做了这道历史悠久的题目,之前不知道是什么原因写到一半不写了,这次再看这道题,有了些思路,其实并不难,只是要把那些条件分开,不可混淆。
线段树区间合并,主要是进行合并。
/* 题意:D代表破坏村庄, R代表修复最后被破坏的那个村庄, Q代表询问包括x在内的最大连续区间是多少 */ #include <iostream> #include <cstdio> #include <stack> #include <cstring> using namespace std; const int maxn=50005; #define lson rt<<1 #define rson rt<<1|1 struct st { int l,r; int lsum, rsum, sum; int mid() { return (l+r)>>1; } int len() { return (r-l+1); } }a[maxn<<2]; void Build_Tree(int rt,int l,int r) { a[rt].l = l; a[rt].r = r; a[rt].lsum = a[rt].rsum = a[rt].sum = a[rt].len(); if(l==r) { return ; } Build_Tree(lson, l, a[rt].mid()); Build_Tree(rson, a[rt].mid()+1, r); } void pushdown(int rt)//进行合并 { a[rt].lsum = a[lson].lsum; a[rt].rsum = a[rson].rsum; if(a[lson].lsum==a[lson].len()) a[rt].lsum = a[lson].lsum+a[rson].lsum; if(a[rson].lsum==a[rson].len()) a[rt].rsum = a[lson].rsum+a[rson].lsum; a[rt].sum = max(a[rt].rsum, a[rt].lsum); a[rt].sum = max(a[rt].sum, a[lson].rsum+a[rson].lsum); } void change(int rt, int index, int x) { if(a[rt].l == index && a[rt].r == index) { a[rt].sum = a[rt].lsum = a[rt].rsum = x; return ; } if(index<=a[rt].mid()) change(lson, index, x); else change(rson, index, x); pushdown(rt); } int Query(int rt, int index) { if(a[rt].sum==0)//找到一点 return 0; if(index<a[rt].l+a[rt].lsum)//左端区间上 return a[rt].lsum; if(index>a[rt].r-a[rt].rsum)//右端区间上 return a[rt].rsum; if(index>a[lson].r-a[lson].rsum && index<a[rson].l+a[rson].lsum)//中间 return a[lson].rsum+a[rson].lsum; if(index<=a[rt].mid()) return Query(lson, index); else return Query(rson, index); } int main() { int m, n; char str[10]; stack<int> sta; while(~scanf("%d%d",&n,&m)) { while(!sta.empty()) sta.pop(); Build_Tree(1,1,n); int x; for(int i=1;i<=m;i++) { scanf("%s",str); if(str[0] == 'D') { scanf("%d", &x); sta.push(x); change(1, x, 0); } else if(str[0] == 'Q') { scanf("%d", &x); int ans = Query(1, x); printf("%d ", ans); } else if(!sta.empty()) { x = sta.top(); sta.pop(); change(1, x, 1); } } } return 0; }