1 条题解
-
0
考虑一些显然不合法的情况,有以下两种:
- 边最后亮灯,但是 和 最后均不亮。
- 边最后不亮,但是 和 最后均亮灯。
先判掉这两种情况之后,可以考虑其他四种可能合法的情况:
- 最后 亮灯, 不亮, 边亮灯,显然可以得出 一定需要在 之后进行最后一次操作,如一种方案是依次进行这些操作: 开灯, 开灯, 关闭,而一开始的 开灯这个操作,可以放到所有操作开头,所以只需要满足 关闭这个操作 在 开灯这个操作后面即可。
- 最后 亮灯, 不亮, 边不亮,可得 一定在 之前进行最后一次操作,同理, 在开头先进行开灯操作,然后需要满足 关闭这个操作在 开灯这个操作前面。
对于最终 不亮 亮,其实就是相反的情况。
另外两种情况( 最后均亮灯以及 最后均不亮),对 和 先后顺序没有限制,如果最后要求均亮灯,则在一开始对 和 进行开灯操作即可。
那么考虑建一张有向图, 表示 必须在 之前进行操作,跑一遍拓扑排序,如果有环就是不合法的,否则就是合法的。
如果合法,根据拓扑序的结果进行开灯或者关灯操作即可。
#include<bits/stdc++.h> using namespace std; #define lowbit(x) x&-x int n,q,a1,a2; int a[500010],b[500010]; priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>st; int tree[2000010],bit[500010]; int posl[500010],posr[500010],ans[500010]; vector<pair<int,int>>v[500010],ql[500010],qr[500010]; int ls(int x){ return x<<1; } int rs(int x){ return x<<1|1; } void update(int now,int x,int l,int r,int num,int typ){ if(l==r){ tree[x]=num; return; } int mid=l+r>>1; if(now<=mid) update(now,ls(x),l,mid,num,typ); else update(now,rs(x),mid+1,r,num,typ); if(typ==0) tree[x]=min(tree[ls(x)],tree[rs(x)]); else tree[x]=max(tree[ls(x)],tree[rs(x)]); } int query(int L,int R,int x,int l,int r,int typ){ if(L<=l&&r<=R) return tree[x]; int mid=l+r>>1; if(L<=mid&&mid<R){ if(typ==0) return min(query(L,R,ls(x),l,mid,typ),query(L,R,rs(x),mid+1,r,typ)); else return max(query(L,R,ls(x),l,mid,typ),query(L,R,rs(x),mid+1,r,typ)); } if(L<=mid) return query(L,R,ls(x),l,mid,typ); return query(L,R,rs(x),mid+1,r,typ); } void addbit(int x,int num){ while(x<=n){ bit[x]+=num; x+=lowbit(x); } } int querybit(int x){ int res=0; while(x>0){ res+=bit[x]; x-=lowbit(x); } return res; } signed main(){ ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); cin>>n>>q; for(int i=1;i<=n;i++){ cin>>a[i]>>b[i]; } for(int i=1;i<=n*4;i++) tree[i]=2e9; st.push({a[1]+b[1],1}); update(1,1,1,n,1,0); posl[1]=0; for(int i=2;i<=n;i++){ while(!st.empty()&&st.top().first<=a[i]){ update(st.top().second,1,1,n,2e9,0); st.pop(); } if(a[i]-b[i]<a[1]){ posl[i]=0; update(i,1,1,n,1,0); st.push({a[i]+b[i],i}); }else{ int temp=upper_bound(a+1,a+i,a[i]-b[i])-a; if(temp==i){ posl[i]=i; update(i,1,1,n,i+1,0); }else{ int temp2=query(temp,i-1,1,1,n,0); posl[i]=temp2-1; posl[i]=min(temp,posl[i]); update(i,1,1,n,posl[i]+1,0); if(posl[i]!=i){ st.push({a[i]+b[i],i}); } } } } for(int i=1;i<=n*4;i++) tree[i]=0; while(!st.empty()) st.pop(); st.push({b[n]-a[n],n}); update(n,1,1,n,n,1); posr[n]=n+1; for(int i=n-1;i>0;i--){ while(!st.empty()&&-st.top().first>=a[i]){ update(st.top().second,1,1,n,0,1); st.pop(); } if(a[i]+b[i]>a[n]){ posr[i]=n+1; update(i,1,1,n,n,1); st.push({b[i]-a[i],i}); }else{ int temp=lower_bound(a+i+1,a+n+1,a[i]+b[i])-a-1; if(temp==i){ posr[i]=i; update(i,1,1,n,i-1,1); }else{ int temp2=query(i+1,temp,1,1,n,1); posr[i]=temp2+1; posr[i]=max(temp,posr[i]); update(i,1,1,n,posr[i]-1,1); if(posr[i]!=i){ st.push({b[i]-a[i],i}); } } } } for(int i=1;i<=n;i++){ //cout<<i<<" "<<posl[i]<<" "<<posr[i]<<endl; if(posl[i]!=0){ v[posl[i]].push_back({i,1}); } if(posr[i]<=n){ v[i].push_back({posr[i],1}); } if(posl[i]>0&&posr[i]<=n){ v[posl[i]].push_back({posr[i],-1}); } } for(int i=1;i<=q;i++){ cin>>a1>>a2; ql[a1].push_back({a2,i}); qr[a2].push_back({a1,i}); } for(int i=1;i<=n;i++){ //cout<<i<<endl; for(auto j:ql[i]){ ans[j.second]-=querybit(j.first); } //cout<<"aaa"<<endl; for(auto j:v[i]){ addbit(j.first,j.second); } //cout<<"bbb"<<endl; for(auto j:qr[i]){ ans[j.second]+=querybit(i); } // cout<<"ccc"<<endl; } for(int i=1;i<=q;i++) cout<<ans[i]<<'\n'; }
- 1
信息
- ID
- 7579
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者