P5445 [APIO2019]路灯
咕了有点久的题。
维护颜色段是个显然的想法。
发现对于一次修改操作无非就是颜色段合并/分裂。
又有一个显然的想法,对于点对之间的关系,考虑 \((a,b)\) 抽象到二维平面。
发现事实上对于合并/分裂都是矩形操作,查询就是单点操作。
考虑如何维护这个单点查,直接暴力做是废的,发现只需要考虑操作到这个点的操作即可。
发现联通时间抽象到时间轴上都是连通块,考虑维护一个后缀时间即可。
即 \((a,b)\) 当前联通了,那么之后都会联通,当前不连通了,那么之后都不会联通。即一个后缀一维的东西,用总时间减下即可。
在机房花 15 min 实现了维护连通块的 set,加上维护二维平面的 DS 即可。
随手写了个大常数的 BIT 套 BIT,3log 只能 81 分。
可以换成别的二维数点结构,比如区间加转差分单点查之类的。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int rd() {
int f=1,sum=0; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
#define N (int)(3e5+5)
struct node {
int l,r;
node() {
}
node(int nl,int nr) {
l=nl; r=nr;
}
bool operator < (const node &rhs) const {
return r<rhs.r;
}
};
set<node>s;
bool a[N];
int n,q,tim,nwans;
bool rdd() {
char ch=getchar();
while(!isdigit(ch)) ch=getchar();
return ch-'0';
}
char rdc() {
char ch=getchar();
while(!isalpha(ch)) ch=getchar();
return ch;
}
int lowbit(int x) {
return x&(-x);
}
unordered_map<int,int>f[N];
void uptf(int id,int x,int v) {
while(x<=n) f[id][x]+=v,x+=lowbit(x);
}
int qryf(int id,int x) {
int res=0; while(x) res+=f[id][x],x-=lowbit(x); return res;
}
void upt(int x,int y,int v) {
if(!x||!y) return ;
while(x<=n) uptf(x,y,v),x+=lowbit(x);
}
int qry(int x,int y) {
if(!x||!y) return 0;
int res=0; while(x) res+=qryf(x,y),x-=lowbit(x); return res;
}
void update(int x,int y,int xx,int yy,int v) {
upt(x,y,v);
upt(x,yy+1,-v);
upt(xx+1,y,-v);
upt(xx+1,yy+1,v);
}
int query(int x,int y) {
if(x>y) return tim;
return qry(x,y);
}
void sins(int x,int y) {
s.insert(node(x,y));
update(x,x,y,y,q-tim);
}
void sdel(int x,int y) {
update(x,x,y,y,tim-q);
}
bool check(int x,int y) {
if(x==y) return 1;
--y;
auto qwq=s.lower_bound(node(0,x));
if(qwq==s.end()) return 0;
if((*qwq).l<=x&&y<=(*qwq).r) return 1;
return 0;
}
void DEE() {
for(auto x=s.begin();x!=s.end();++x) cout<<(*x).l<<" "<<(*x).r<<'\n';
}
void ins(int x) {
if(s.empty()) {
sins(x,x);
return ;
}
if(s.size()==1) {
auto qwq=s.begin(); int al=(*qwq).l,ar=(*qwq).r;
if(ar+1==x) {
s.erase(qwq); sdel(al,ar); sins(al,x);
} else if(al-1==x) {
s.erase(qwq); sdel(al,ar); sins(x,ar);
} else {
sins(x,x);
}
return ;
}
auto L=s.lower_bound(node(0,x));
if(L==s.end()) {
auto pre=s.end(); --pre;
if(pre->r+1==x) {
int pl=pre->l,pr=pre->r;
s.erase(pre); sdel(pl,pr); sins(pl,x);
} else {
sins(x,x);
}
} else if(L!=s.begin()) {
auto R=L; --L;
int al=(*L).l,ar=(*L).r,bl=(*R).l,br=(*R).r;
if(ar+1==x) {
if(bl-1==x) {
s.erase(L); s.erase(R);
sdel(al,ar); sdel(bl,br);
sins(al,br);
} else {
sdel(al,ar);
s.erase(L); sins(al,x);
}
} else {
if(bl-1==x) {
sdel(bl,br);
s.erase(R); sins(x,br);
} else {
sins(x,x);
}
}
} else {
int al=(*L).l,ar=(*L).r;
if(al-1==x) {
s.erase(L); sdel(al,ar); sins(x,ar);
} else {
sins(x,x);
}
}
}
void del(int x) {
auto R=s.lower_bound(node(0,x));
int al=R->l,ar=R->r;
sdel(al,ar);
s.erase(R);
if(al<=x-1) sins(al,x-1);
if(x+1<=ar) sins(x+1,ar);
}
signed main() {
n=rd(); q=rd();
for(int i=1;i<=n;i++) {
a[i]=rdd();
if(a[i]) ins(i);
}
for(tim=1;tim<=q;tim++) {
if(rdc()=='t') {
int x=rd();
if(a[x]) del(x);
else ins(x);
a[x]^=1;
// DE();
} else {
int x=rd(),y=rd();
printf("%lld\n",query(x,y-1)-(check(x,y)?q-tim:0));
}
}
return 0;
}