题目链接:http://codeforces.com/gym/101879/problem/G
题意:有n个警察,第i个警察看管监狱的区间是【Li,Ri】。
有两种操作:C i l r :把第i个警察的区间变为【l,r】。
?l r :询问从第l个警察到第r个警察共同看管的区间长度是多少
我的思路:以警察来建线段树,每次维护一个区间里最大的l和最小的r,这样很容易得到这个区间里的警察的公共区间的长度就是r-l+1。最后就变成了单点更新+区间询问的线段树。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+3;
#define lson rt<<1
#define rson rt<<1|1
ll xl[maxn],xr[maxn];
struct node//个人觉得用结构体会简便一点
{
ll l,r,len;
}tree[maxn<<2];
int cnt;
void bulid(ll rt,ll l,ll r)
{
if(l==r)
{
tree[rt].l=xl[++cnt];
tree[rt].r=xr[cnt];
tree[rt].len=xr[cnt]-xl[cnt]+1;
return;
}
ll mid=(l+r)>>1;
bulid(lson,l,mid);
bulid(rson,mid+1,r);
tree[rt].l=max(tree[lson].l,tree[rson].l);//向上更新
tree[rt].r=min(tree[lson].r,tree[rson].r);
tree[rt].len=tree[rt].r-tree[rt].l+1;
}
void updata(ll rt,ll l,ll r,ll x,ll newl,ll newr)
{
if(l==x&&r==x)
{
tree[rt].l=newl;
tree[rt].r=newr;
tree[rt].len=tree[rt].r-tree[rt].l+1;
return;
}
ll mid=(l+r)>>1;
if(x<=mid)updata(lson,l,mid,x,newl,newr);
else updata(rson,mid+1,r,x,newl,newr);
tree[rt].l=max(tree[lson].l,tree[rson].l);//向上更新
tree[rt].r=min(tree[lson].r,tree[rson].r);
tree[rt].len=tree[rt].r-tree[rt].l+1;
}
node query(ll rt,ll l,ll r,ll x,ll y)
{
if(l>=x&&r<=y)
{
return tree[rt];
}
ll mid=(l+r)>>1;
node a,b,c;
bool ff=false;
if(y<=mid)a=query(lson,l,mid,x,y);
else if(x>=mid+1)a=query(rson,mid+1,r,x,y);
else a=query(lson,l,mid,x,mid),b=query(rson,mid+1,r,mid+1,y),ff=true;
if(ff)//如果是左右两个子树都有的话,就要重新更新最大的l和最小的r
{
c.l=max(a.l,b.l);
c.r=min(a.r,b.r);
c.len=c.r-c.l+1;
return c;
}
else return a;
}
int main()
{
int n,q;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)scanf("%lld%lld",&xl[i],&xr[i]);
cnt=0;
bulid(1,1,n);
char o[2];
int tp1,tp2,tp3;
for(int i=1;i<=q;i++)
{
scanf("%s",o);
if(o[0]=='?')
{
scanf("%d%d",&tp1,&tp2);
node ans=query(1,1,n,tp1,tp2);
printf("%lld\n",ans.len>=0?ans.len:0);//如果一个区间的长度是负的,也就是没有公共区间
}
else
{
scanf("%d%d%d",&tp1,&tp2,&tp3);
updata(1,1,n,tp1,tp2,tp3);
}
}
return 0;
}