bzoj5017 [Snoi2017]炸弹
好长时间没写博客了...春季学期的日记似乎是没怎么写, 回头写个总结反思放上来...
这个题首先一看就是图论题, 看两眼就是需要数据结构优化的图论题, 而且肯定是用线段树. 看三眼发现需要tarjan求一下强连通分量.
看四眼看出来引爆一个炸弹, 最终能够引爆的所有炸弹一定是一个连续区间内的所有炸弹, 然后就发现只需要求每个炸弹能够引爆的编号最小和最大的炸弹
也就是从强连通分量缩点之后的DAG上算一下每个SCC能够到达的编号最小/最大的炸弹.
思路清晰自然, 是个不错的题.
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=1000005;
struct edge{
int to, next;
}lst[maxn*40];int len=1;
int first[maxn];
void addedge(int a,int b){
lst[len].to=b;
lst[len].next=first[a];
first[a]=len++;
}
int N;
ll X[maxn], R[maxn];
int left[maxn], right[maxn];
struct seg{
static int ID;
int l,r,id;
seg* ch[2];
seg(int a,int b):l(a),r(b){
if(a==b)id=a;
else id=++ID;
ch[0]=ch[1]=0;
}
};
int seg::ID=1;
void build(seg* &root, int L, int R){
root = new seg(L,R);
if(L==R)return;
build(root->ch[0],L,(L+R)>>1);
build(root->ch[1],((L+R)>>1)+1,R);
addedge(root->id, root->ch[0]->id);
addedge(root->id, root->ch[1]->id);
}
void add(seg* rt, int from, int L, int R){
if(L <= rt->l && rt->r <= R){
if(from!=rt->id)addedge(from, rt->id);
}else{
int mid=(rt->l+rt->r)>>1;
if(L<=mid)add(rt->ch[0],from,L,R);
if(R>mid)add(rt->ch[1],from,L,R);
}
}
int dfn[maxn], low[maxn], T;
int stk[maxn],top=0;
bool ins[maxn];
vector<int> scc[maxn];int cntscc=0;
int belong[maxn];
void dfs(int x){
dfn[x]=low[x]=++T;
stk[top++]=x;ins[x]=true;
for(int pt=first[x];pt;pt=lst[pt].next){
if(!dfn[lst[pt].to]){
dfs(lst[pt].to);
if(low[lst[pt].to]<low[x])low[x]=low[lst[pt].to];
}else if(ins[lst[pt].to] && dfn[lst[pt].to]<low[x])low[x]=dfn[lst[pt].to];
}
if(low[x] == dfn[x]){
++cntscc;
do{
scc[cntscc].push_back(stk[--top]);
belong[stk[top]]=cntscc;
ins[stk[top]]=false;
}while(stk[top]!=x);
}
}
void tarjan(){
for(int i=1;i<=N;++i){
if(!dfn[i])dfs(i);
}
}
int lo[maxn], hi[maxn], vis[maxn];
void DFS(int x){
vis[x]=1;
for(vector<int>::iterator p=scc[x].begin();p!=scc[x].end();++p){
if(1<=(*p) &&(*p)<=N){
if((*p)>hi[x])hi[x]=*p;
if((*p)<lo[x])lo[x]=*p;
}
for(int pt=first[*p];pt;pt=lst[pt].next){
int y=belong[lst[pt].to];
if(!vis[y]){
DFS(y);
}
if(hi[y]>hi[x])hi[x]=hi[y];
if(lo[y]<lo[x])lo[x]=lo[y];
}
}
}
void dp(){
for(int i=1;i<=cntscc;++i){
lo[i]=N+1;hi[i]=0;
}
for(int i=1;i<=cntscc;++i){
if(!vis[i])DFS(i);
}
}
int main(){
scanf("%d",&N);
for(int i=1;i<=N;++i){
scanf("%lld%lld",X+i, R+i);
}
for(int i=1;i<=N;++i){
left[i]=lower_bound(X+1,X+N+1, X[i]-R[i])-X;
right[i]=upper_bound(X+1, X+N+1, X[i]+R[i])-X-1;
}
seg::ID=N;
seg *root;
build(root, 1, N);//while(1);
for(int i=1;i<=N;++i){
add(root,i,left[i],right[i]);
}
tarjan();
dp();
int ans=0;
int mod=(int)(1e9+7);
for(int i=1;i<=N;++i){
ans = (ans + i * 1ll * (hi[belong[i]]-lo[belong[i]]+1))%mod;
}
printf("%d\n",ans);
return 0;
}