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;
}
posted @ 2022-02-25 13:40  FxorG  阅读(56)  评论(0编辑  收藏  举报