1540-线段树区间合并操作

来源:互联网 发布:2002数据库怎么使用 编辑:程序博客网 时间:2024/05/20 14:15

#include<stdio.h>#include<iostream>#include<stack>#include<cstring>using namespace std;const int MAX=1000000;struct pr {    int lsum,rsum,msum;    int left,right;                   }tr[MAX+10];int n,m;inline int ll(int k) {return 2*k;}          inline int rr(int k) {return 2*k+1;}         inline int mid(int kk1,int kk2) {return (kk1+kk2)>>1;}void pushup(int k){//m=r-l+1;    int l=tr[k].left,r=tr[k].right;    int mi=mid(l,r);    tr[k].lsum =tr[ll(k)].lsum;    tr[k].rsum =tr[rr(k)].rsum;    if (tr[k].lsum == mi-l+1) tr[k].lsum+=tr[rr(k)].lsum;    if (tr[k].rsum == r-mi) tr[k].rsum+=tr[ll(k)].rsum;    tr[k].msum = max(tr[rr(k)].lsum+tr[ll(k)].rsum,max(tr[ll(k)].msum,tr[rr(k)].msum));    return;}void build(int k,int s,int t) {    tr[k].left=s;tr[k].right=t;    if(s==t) {tr[k].rsum=tr[k].lsum=tr[k].msum=1;return;}                   build(ll(k),s,mid(s,t));    build(rr(k),mid(s,t)+1,t);    pushup(k);        //pushup}void modify(int k,int in,int x) {    int l=tr[k].left,r=tr[k].right;    if(l==r) {        if(x==1)            tr[k].lsum=tr[k].msum=tr[k].rsum=0;        else            tr[k].lsum=tr[k].msum=tr[k].rsum=1;        return ;    }    int mi=mid(l,r);    if(in<=mi) modify(ll(k),in,x);    else if(in>mi) modify(rr(k),in,x);    pushup(k);}int query(int k,int x) {    int l=tr[k].left,r=tr[k].right;    if(l==r||tr[k].msum==0||tr[k].msum==r-l+1) return tr[k].msum;    int mi=mid(l,r);    int res=0;    if (x<=mi){        if(tr[ll(k)].right-tr[ll(k)].rsum+1<=x)            res=query(ll(k),x)+query(rr(k),mi+1);        else            res=query(ll(k),x);    }    else if(x>mi){        if(tr[rr(k)].lsum+tr[rr(k)].left-1>=x)            res=query(rr(k),x)+query(ll(k),mi);        else            res=query(rr(k),x);    }    return res;}int main(){    while(cin>>n>>m){        build(1,1,n);        char s[10];        int x;        stack<int> Q;        for(int i=0;i<m;i++){            scanf("%s",s);            if(s[0]=='D'){                scanf("%d",&x);                Q.push(x);                modify(1,x,1);            }            else if(s[0]=='Q'){                scanf("%d",&x);                printf("%d\n",query(1,x));            }            else{                int y=Q.top();                Q.pop();                modify(1,y,0);            }        }    }    return 0;}

这是一道基础的线段树合并基本操作。

题意就是单点修改,然后查询单点所在的连续合法区间,初始化都是合法的。

这题的考点应该就是查询部分。


查询部分单独拿出来说一下,

if (x<=mi){        if(tr[ll(k)].right-tr[ll(k)].rsum+1<=x)            res=query(ll(k),x)+query(rr(k),mi+1);        else            res=query(ll(k),x);    }
就拿查询点在mid的左来举个栗子,考虑到在左面如果只查询左区间很可能得到错误答案(例如x在rsum里那么q(x)的答案就会漏掉r右边的部分),所以在另一个区间查他的左端点就可以啦,所以这题大致就是这样的了。。其他类比就行了。。


蒟蒻写的搓大家见谅。。。继续努力。。鲤鱼王加油!


0 0
原创粉丝点击