LG P5445 [APIO2019]路灯

Description

一辆自动驾驶的出租车正在 Innopolis 的街道上行驶。该街道上有 $n+1$ 个停车站点,它们将街道划分成了 $n$ 条路段。每一路段都拥有一个路灯。当第 $i$ 个路灯亮起,它将照亮连接第 $i$ 与第 $i+1$ 个站点的路段。否则这条路段将是黑暗的。

安全起见,出租车只能在被照亮的路段上行驶。换言之,出租车能从站点 $a$ 出发到达站点 $b(a < b)$ 的条件是:连接站点 $a$ 与 $a+1,a+2 \cdots b-1$ 与 $b$ 的路段都被照亮。

在经过一些意外故障或修理之后,街道上的路灯可能是亮起的,也可能是熄灭的。

现在给定 $0$ 时刻时,街道上路灯的初始状态。之后 $1,2,\ldots,q$ 时刻,每时刻会发生下列两种事件之一:

toggle i:切换第 $i$ 个路灯的状态。具体地说,若路灯原来亮起,则现在将熄灭;若路灯原来熄灭,则现在将亮起。

query a b:出租车部门的负责人想知道,从 $a$ 时刻起到当前时刻,有多少个时刻满足:出租车能够从站点 $a$ 出发到达站点 $b$。

请你帮助出租车部门的负责人回答他们的问题。

Solution

点亮一个路灯即为连接两个明亮的路段,维护所有明亮的路段可以使用set

维护答案时,若连接$(l_1,r_1)$和$(l_2,r_2)$,那么对于区间$[l_1\cdots l_2,r_1\cdots r_2]$,区间由暗变亮了,相当于矩形区间加$q-t$,$t$为此时时间

熄灭路灯同理,求答案时相当于单点求值,若此时整个区间仍然明亮,答案需要减去$q-t$

LG P5445 [APIO2019]路灯
#include<iostream>
#include<cstdio>
#include<set>
using namespace std;
int n,q,rt[300005],cnt;
char str[300005],opt[10];
struct Node{
    int l,r;
    bool operator <(const Node &z)const{return r<z.r;}
};
struct SGT{
    int lc,rc,val;
}tr[30000005];
set<Node>s;
inline int read(){
    int f=1,w=0;
    char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
    return f*w;
}
void update(int &i,int l,int r,int p,int v){
    if(!i)i=++cnt;
    tr[i].val+=v;
    if(l==r)return;
    int mid=l+r>>1;
    if(p<=mid)update(tr[i].lc,l,mid,p,v);
    else update(tr[i].rc,mid+1,r,p,v);
}
int query(int i,int l,int r,int L,int R){
    if(!i)return 0;
    if(L<=l&&r<=R)return tr[i].val;
    int mid=l+r>>1,ret=0;
    if(L<=mid)ret+=query(tr[i].lc,l,mid,L,R);
    if(R>mid)ret+=query(tr[i].rc,mid+1,r,L,R);
    return ret;
}
void add(int pos,int y,int v){while(pos<=n+2)update(rt[pos],1,n+2,y,v),pos+=pos&-pos;}
void solve(int x1,int y1,int x2,int y2,int v){add(x1,y1,v),add(x2+1,y2+1,v),add(x1,y2+1,-v),add(x2+1,y1,-v);}
int ask(int x,int y){
    int ret=0;
    while(x)ret+=query(rt[x],1,n+2,1,y),x-=x&-x;
    return ret;
}
int main(){
    n=read(),q=read(),scanf("%s",str+1);
    for(int i=1;i<=n+1;i++)s.insert((Node){i,i});
    for(int i=1;i<=n;i++)if(str[i]=='1'){
        set<Node>::iterator it=s.lower_bound((Node){0,i});
        int l=(*it).l;
        s.erase(it),s.erase((Node){i+1,i+1}),s.insert((Node){l,i+1});
    }
    for(set<Node>::iterator it=s.begin();it!=s.end();it++)solve((*it).l,(*it).l,(*it).r,(*it).r,q);
    for(int i=1;i<=q;i++){
        scanf("%s",opt);
        if(opt[0]=='t'){
            int x=read();
            if(str[x]=='1'){
                set<Node>::iterator it=s.lower_bound((Node){0,x});
                int l1=(*it).l,r1=x,l2=x+1,r2=(*it).r;
                solve(l1,l2,r1,r2,i-q),s.erase(it),s.insert((Node){l1,r1}),s.insert((Node){l2,r2}),str[x]='0';
            }
            else{
                set<Node>::iterator it=s.lower_bound((Node){0,x});
                int l1=(*it).l,r1=x,l2=x+1,r2=0;
                ++it,l2=x+1,r2=(*it).r,solve(l1,l2,r1,r2,q-i),s.erase(it),s.erase((Node){l1,r1}),s.insert((Node){l1,r2}),str[x]='1';
            }
        }
        else{
            int x=read(),y=read(),ans=ask(x,y);
            set<Node>::iterator it1=s.lower_bound((Node){0,x}),it2=s.lower_bound((Node){0,y});
            printf("%d\n",ans-(q-i)*((*it1).l==(*it2).l));
        }
    }
    return 0;
}
路灯

 

上一篇:数据库迁移


下一篇:P5445-[APIO2019]路灯【set,树状数组套线段树】