Solution
- 此题可以将一个炸弹向它可以引爆的炸弹连一条有向边
- 然后在建成的图中搜索一个炸弹沿有向边能到的炸弹数为多少
- 似乎可以用强联通分量缩点来优化?
由于每个炸弹能引爆的炸弹必定是连续的一段,所以缩点时可以记录每个缩后的点代表哪一段炸弹
缩完点后dfs一遍找出缩后的点能引爆哪一段
但出题人太恶意,需要连n2条边。。。
由于连的边总是一段区间,我们考虑能不能用线段树优化
建一棵有n个叶子节点的线段树(父亲向儿子连边,数量级为n),把每个炸弹作为编号对应的叶子节点
然后连边时向对应线段连边,总的连边数在nlogn数量级内
Code
#include <cstdio> #include <cstdlib> #include <vector> #include <cstring> #include <algorithm> #define ll long long #define mid ((l+r)>>1) #define lc (g<<1) #define rc ((g<<1)|1) using namespace std; const int N=5e5+10,M=2e6+10,P=1e9+7; vector <int> link[M],son[M],re[M]; int n,id[N],scc,d[M],le[M],ri[M],m; int top,dfn[M],low[M],tot,st[M],in[M],ans; ll x[N],r[N]; struct node { int l,r; inline node(int l=0,int r=0):l(l),r(r){}; }f[M]; void build(int g,int l,int r) { f[g]=node(l,r); m=max(m,g); if(l==r) { id[l]=g; return; } link[g].push_back(lc); link[g].push_back(rc); build(lc,l,mid); build(rc,mid+1,r); } void add(int g,int l,int r,int ul,int ur,int v) { if(ul<=l && r<=ur) { link[v].push_back(g); return; } if(ur<=mid) add(lc,l,mid,ul,ur,v); else if(ul>mid) add(rc,mid+1,r,ul,ur,v); else add(lc,l,mid,ul,mid,v),add(rc,mid+1,r,mid+1,ur,v); } void tarjan(int u) { dfn[u]=low[u]=++tot; st[++top]=u,in[u]=1; int size=link[u].size(); for(int i=0;i<size;i++) { int v=link[u][i]; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(in[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { scc++; int z=0; do { z=st[top--]; d[z]=scc,in[z]=0; le[scc]=min(le[scc],f[z].l); ri[scc]=max(ri[scc],f[z].r); }while(z!=u); } } void dfs(int u) { in[u]=1; int size=re[u].size(); for(int i=0;i<size;i++) { int v=re[u][i]; if(!in[v]) dfs(v); le[u]=min(le[u],le[v]); ri[u]=max(ri[u],ri[v]); } } int query(int x) { int u=d[id[x]]; return ri[u]-le[u]+1; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld%lld",&x[i],&r[i]); build(1,1,n); for(int i=1;i<=n;i++) { int L=lower_bound(x+1,x+1+n,x[i]-r[i])-x; int R=upper_bound(x+1,x+1+n,x[i]+r[i])-x-1; add(1,1,n,L,R,id[i]); } memset(le,0x3f,sizeof(le)); tarjan(1); for(int u=1;u<=m;u++) { int size=link[u].size(); for(int i=0,v;i<size;i++) if(d[v=link[u][i]]!=d[u]) re[d[u]].push_back(d[v]); } dfs(d[1]); for(int i=1;i<=n;i++) ans=(ans+(ll)query(i)*i%P)%P; printf("%d",ans); return 0; }