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

1|0正题

题目链接:https://www.luogu.com.cn/problem/P5445


1|1题目大意

n+1个点,ii+1个点之间有一条边,q个操作

  1. 断开/连接第xx+1之间的边
  2. 询问目前为止ab点在多少个操作后是联通的(包括开始前)

1|2解题思路

粗略的思想是我们可以用set来维护联通的块,但是这样很难统计答案,我们需要加上点其他东西。

考虑使用一个(n+1)×(n+1)的矩形来表示这个图的联通性,第(i,j)个点储存目前的操作为止ij到结束会联通多久。

以下矩形用(x1,y1,x2,y2)来表示
为什么用矩形,因为每次都一定是连接两个区间或者断开一个区间,所以每次操作可以视为矩形操作。

为什么是目前的操作到结束位置,因为如果直接维护答案那么每次操作后有些位置的答案要加一,这样存就保证了一个静止状态,方便赋值。

对于一次操作连接[l1,r1][l2,r2]我们可以将矩形(l1,l2,r1,r2)这个矩形加上一个qtt表示当前是第几个操作),断开的话就减去就好了。

需要注意如果这个时候询问的两个区间联通,那么询问出来的答案是到结束而不是到目前为止的,所以要减去一个qt

时间复杂度O(nlog2n)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<set> #define lowbit(x) (x&-x) using namespace std; const int N=3e5+10,M=N<<7; struct line{ int l,r; line(int ll=0,int rr=0) {l=ll;r=rr;} }; bool operator<(line x,line y) {return x.r<y.r;} int n,q,rt[N]; char st[N]; set<line> s; set<line>::iterator it; struct Seq_Tree{ int w[M],ls[M],rs[M],cnt; void Change(int &x,int L,int R,int pos,int val){ if(!x)x=++cnt;w[x]+=val; if(L==R)return; int mid=(L+R)>>1; if(pos<=mid)Change(ls[x],L,mid,pos,val); else Change(rs[x],mid+1,R,pos,val); return; } int Ask(int x,int L,int R,int l,int r){ if(!x)return 0; if(L==l&&R==r)return w[x]; int mid=(L+R)>>1; if(r<=mid)return Ask(ls[x],L,mid,l,r); if(l>mid)return Ask(rs[x],mid+1,R,l,r); return Ask(ls[x],L,mid,l,mid)+Ask(rs[x],mid+1,R,mid+1,r); } }T; void Change(int x,int y,int val){ if(y>n)return; while(x<=n){ T.Change(rt[x],1,n,y,val); x+=lowbit(x); } return; } int Ask(int x,int y){ int ans=0; while(x){ ans+=T.Ask(rt[x],1,n,1,y); x-=lowbit(x); } return ans; } void Updata(int x1,int x2,int y1,int y2,int val){ Change(x1,y1,val);Change(x2+1,y2+1,val); Change(x2+1,y1,-val);Change(x1,y2+1,-val); return; } void Cut(int x,int t){ it=s.lower_bound(line(x,x)); int l=(*it).l,r=(*it).r; s.erase(it); Updata(l,x,x+1,r,t-q); s.insert(line(l,x)); s.insert(line(x+1,r)); return; } void Link(int x,int t){ it=s.lower_bound(line(x,x)); int x1=(*it).l,y1=(*it).r;s.erase(it); it=s.lower_bound(line(x,x)); int x2=(*it).l,y2=(*it).r;s.erase(it); Updata(x1,y1,x2,y2,q-t); s.insert(line(x1,y2)); return; } int main() { // printf("%d\n",sizeof(T)>>20); scanf("%d%d",&n,&q); scanf("%s",st+1);n++; s.insert((line){1,n}); Updata(1,n,1,n,q); for(int i=1;i<n;i++) if(st[i]=='0')Cut(i,0); for(int i=1;i<=q;i++){ char op[10];scanf("%s",op); if(op[0]=='q'){ int l,r;scanf("%d%d",&l,&r); it=s.lower_bound(line(l,l)); int a=(*it).r; it=s.lower_bound(line(r,r)); int b=(*it).r; printf("%d\n",Ask(l,r)-(a==b)*(q-i)); } else{ int x;scanf("%d",&x); if(st[x]=='0') st[x]='1',Link(x,i); else st[x]='0',Cut(x,i); } } return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/14277495.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(63)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示