您的位置:首页 > 其它

1540-线段树区间合并操作

2016-04-07 16:11 344 查看
#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右边的部分),所以在另一个区间查他的左端点就可以啦,所以这题大致就是这样的了。。其他类比就行了。。

蒟蒻写的搓大家见谅。。。继续努力。。鲤鱼王加油!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: