【題解】[SNOI2017]炸彈

[SNOI2017]炸彈

\(\text{Solution:}\)

我們發現也就是每次將一個點往周圍的點連邊然後求每個點能到達的節點數。

點對區間連邊,考慮線段樹優化建圖。

建完之後跑縮點,然後我們發現不會 DAG 上求這個問題。

但是我們又可以發現,我們可以在縮點的時候求出每個點往左往右能到達的最遠點。

這樣就可以直接獲得答案了。

#include<bits/stdc++.h>
using namespace std;
typedef double db;
#define int long long
const int mod=1e9+7;
const db eps=1e-14;
inline int Max(int x,int y){return x>y?x:y;}
inline int Min(int x,int y){return x<y?x:y;}
inline db Max(db x,db y){return x-y>eps?x:y;}
inline db Min(db x,db y){return x-y<eps?x:y;}
inline int Add(int x,int y,int M=mod){return (x+y)%M;}
inline int Mul(int x,int y,int M=mod){return 1ll*x*y%M;}
inline int Dec(int x,int y,int M=mod){return (x-y+M)%M;}
inline int Abs(int x){return x<0?-x:x;}
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s*w;
}
inline void write(int x){
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
inline int qpow(int x,int y){
	int res=1;
	while(y){
		if(y&1)res=Mul(res,x);
		x=Mul(x,x);y>>=1;
	}
	return res;
}
typedef pair<int,int> pr;
#define fi first
#define se second
#define mk make_pair
#define pb emplace_back
#define poly vector<int>
const int N=4e6+10;


namespace Refined_heart{
	int tot,pos[N][2],ls[N],rs[N],rt,node;
	int head[N],tcnt,n,lb[N],rb[N],siz[N];
	int vis[N],dfn[N],low[N],st[N],top;
	int inst[N],dfstime,scc,col[N],lq[N],rq[N];
	struct E{
		int nxt,to,pre;
		E(int xx=0,int yy=0,int zz=0){nxt=xx,to=yy,pre=zz;}
	}e[N];
	struct boom{
		int x,r;
		boom(int xx=0,int yy=0){x=xx;r=yy;}
	}p[N];
	inline void link(int x,int y,int p){
		e[++tcnt]=E(head[x],y,p);
		head[x]=tcnt;
	} 
	E eg[N];
	int Head[N],Tcnt;
	inline void Link(int x,int y){
		eg[++Tcnt]=E(Head[x],y);
		Head[x]=Tcnt;
	}
	void tarjan(int x){
		dfn[x]=low[x]=++dfstime;
		st[++top]=x;inst[x]=1;
		for(int i=head[x];i;i=e[i].nxt){
			int j=e[i].to;
			if(!dfn[j]){
				tarjan(j);
				low[x]=Min(low[x],low[j]);
			}
			else if(inst[j])low[x]=Min(low[x],dfn[j]);
		}
		if(low[x]==dfn[x]){
			int y=0;++scc;
			while(y=st[top--]){
				if(y<=n)siz[scc]++;
				col[y]=scc;
				inst[y]=0;
				if(x==y)break;
			}
		}
	}
	void build(int &x,int l,int r){
		x=++node;
		if(l==r){
			pos[x][0]=pos[x][1]=l;
			return;
		}
		int mid=(l+r)>>1;
		build(ls[x],l,mid);
		build(rs[x],mid+1,r);
		pos[x][0]=++tot;pos[x][1]=++tot;
		link(pos[x][1],pos[ls[x]][1],pos[x][1]);
		link(pos[x][1],pos[rs[x]][1],pos[x][1]);
		link(pos[ls[x]][0],pos[x][0],pos[ls[x]][0]);
		link(pos[rs[x]][0],pos[x][0],pos[rs[x]][0]);
	}
	void Edge(int x,int L,int R,int l,int r,int cur,int opt){
		if(L>=l&&R<=r){
			if(opt==0)link(pos[x][0],cur,pos[x][0]);
			else link(cur,pos[x][1],cur);
			return;
		}
		int mid=(L+R)>>1;
		if(l<=mid)Edge(ls[x],L,mid,l,r,cur,opt);
		if(mid<r)Edge(rs[x],mid+1,R,l,r,cur,opt);
	}
	void findpos(int pos){
		int l=1,r=pos;
		while(l<=r){
			int mid=(l+r)>>1;
			if(p[pos].x-p[pos].r>p[mid].x)l=mid+1;
			else r=mid-1,lb[pos]=mid;
		}
		l=pos,r=n;
		while(l<=r){
			int mid=(l+r)>>1;
			if(p[pos].x+p[pos].r<p[mid].x)r=mid-1;
			else l=mid+1,rb[pos]=mid;
		}
	}
	int V[N];
	void dfs(int x){
		V[x]=1;
		for(int i=Head[x];i;i=eg[i].nxt){
			int j=eg[i].to;
			if(V[j]){
				lq[x]=Min(lq[x],lq[j]);
				rq[x]=Max(rq[x],rq[j]);
				continue;
			}
			dfs(j);
			lq[x]=Min(lq[x],lq[j]);
			rq[x]=Max(rq[x],rq[j]);
		}
	}
	void solve(){
		freopen("in.txt","r",stdin);
		n=read();
		for(int i=1;i<=n;++i){
			int u=read(),v=read();
			p[i]=boom(u,v);
		}
		sort(p+1,p+n+1,[&](boom x,boom y){return x.x<y.x;});
		for(int i=1;i<=n;++i)findpos(i);
		tot=n;build(rt,1,n);
		for(int i=1;i<=n;++i)Edge(rt,1,n,lb[i],rb[i],i,1);
		for(int i=1;i<=n;++i)if(!dfn[i])tarjan(i);
		for(int i=1;i<=tcnt;++i){
			int u=e[i].pre,v=e[i].to;
			int cu=col[u],cv=col[v];
			if(cu==cv)continue;
			Link(cu,cv);
		}
		memset(lq,0x3f,sizeof lq);
		memset(rq,-0x3f,sizeof rq);
		for(int i=1;i<=n;++i)lq[col[i]]=Min(lq[col[i]],i),rq[col[i]]=Max(rq[col[i]],i);
		for(int i=1;i<=scc;++i)if(!V[i])dfs(i);
		int ans=0;
		for(int i=1;i<=n;++i){
			int pos=col[i];
			ans=Add(ans,Mul(i,rq[pos]-lq[pos]+1));
		}
		printf("%lld\n",ans);
	}
}
signed main(){
	Refined_heart::solve();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章