• [BZOJ5017] [SNOI2017] 炸弹


    题目链接

    BZOJ:https://lydsy.com/JudgeOnline/problem.php?id=5017.

    LOJ:https://loj.ac/problem/2255.

    洛谷:https://www.luogu.org/problemnew/show/P5025.

    Solution

    这题有一个比较显然的暴力:

    • 对于一个点(x),我们二分出(l,r)表示(x)爆炸可以波及到的点的范围,然后我们从(x)([l,r])分别连边。

    • 建完图之后我们(tarjan)缩点,然后对于点(x)我们记录(L_x,R_x)表示(x)爆炸考虑连锁反应可以炸到的范围,这个在(DAG)(dp)就可以了,这个点的答案就是(R_x-L_x+1)

    那么正解其实就很显然了,由于每次建边都是从一个点连向一个区间,那么直接线段树优化建图就好了。

    具体的,我们建一棵(1sim n)的线段树,父亲向儿子连有向边,然后对于(x o [l,r]),我们把([l,r])拆成(O(log n))个区间,然后我们就只需要建(O(log n))条边了,然后缩点就直接在这个线段树上跑就好了。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define ll long long 
    
    void read(ll &x) {
        x=0;ll f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    #define ls p<<1
    #define rs p<<1|1
    #define mid ((l+r)>>1)
    
    const int maxn = 5e5+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
    
    int col,n,bel[maxn<<2],rev[maxn<<2];
    
    struct Graph {
    	int head[maxn<<2],tot,deg[maxn<<2],l[maxn<<2],r[maxn<<2],t[maxn<<2],top;
    	struct edge{int to,nxt;}e[maxn<<3];
    
    	void ins(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot,deg[v]++;}
    	
    	void toposort() {
    		queue<int > q;
    		for(int i=1;i<=col;i++) if(!deg[i]) q.push(i);
    		while(!q.empty()) {
    			int now=q.front();q.pop();t[++top]=now;
    			for(int i=head[now];i;i=e[i].nxt)
    				if(!--deg[e[i].to]) q.push(e[i].to);
    		}
    		reverse(t+1,t+top+1);
    		for(int x=1;x<=top;x++) {
    			for(int i=head[x];i;i=e[i].nxt)
    				l[x]=min(l[x],l[e[i].to]),r[x]=max(r[x],r[e[i].to]);
    		}
    	}
    	
    	void solve() {
    		int ans=0;
    		for(int i=1;i<=n;i++)
    			ans=(ans+1ll*i*(r[bel[rev[i]]]-l[bel[rev[i]]]+1)%mod)%mod;
    		write(ans);
    	}
    }G;
    
    ll pos[maxn],R[maxn];
    int head[maxn<<2],tot,dfn[maxn<<2],low[maxn<<2],dfn_cnt,sta[maxn<<2],top,vis[maxn<<2],id[maxn<<2];
    struct edge{int to,nxt;}e[maxn<<4];
    
    void ins(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
    
    void build(int p,int l,int r) {
    	if(l==r) return rev[l]=p,id[p]=l,void();
    	ins(p,ls),ins(p,rs);
    	build(ls,l,mid),build(rs,mid+1,r);
    }
    
    void insert(int p,int l,int r,int x,int y,int t) {
    	if(x<=l&&r<=y) return ins(t,p),void();
    	if(x<=mid) insert(ls,l,mid,x,y,t);
    	if(y>mid) insert(rs,mid+1,r,x,y,t);
    }
    
    void tarjan(int x) {
    	dfn[x]=low[x]=++dfn_cnt,sta[++top]=x,vis[x]=1;
    	for(int v,i=head[x];i;i=e[i].nxt)
    		if(!dfn[v=e[i].to]) tarjan(v),low[x]=min(low[x],low[v]);
    		else if(vis[v]) low[x]=min(low[x],dfn[v]);
    	if(low[x]==dfn[x]) {
    		col++;int r;G.l[col]=1e9;
    		while(sta[top+1]!=x) {
    			bel[r=sta[top--]]=col,vis[r]=0;
    			if(id[r]) {
    				G.l[col]=min(G.l[col],id[r]);
    				G.r[col]=max(G.r[col],id[r]);
    			}
    		}
    	}
    }
    
    int main() {
        scanf("%d",&n);build(1,1,n);
    	for(int i=1;i<=n;i++) read(pos[i]),read(R[i]);
    	for(int i=1;i<=n;i++) {
    		int l=lower_bound(pos+1,pos+n+1,pos[i]-R[i])-pos;
    		int r=upper_bound(pos+1,pos+n+1,pos[i]+R[i])-pos-1;
    		insert(1,1,n,l,r,rev[i]);
    	}
    	for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
    	for(int x=1;x<=n;x++)
    		for(int i=head[x];i;i=e[i].nxt)
    			if(bel[e[i].to]!=bel[x]) G.ins(bel[x],bel[e[i].to]);
    	G.toposort(),G.solve();
    	return 0;
    }
    
  • 相关阅读:
    微信小程序入门教程之三:脚本编程
    微信小程序入门教程之四:API 使用
    微信小程序入门教程之一:初次上手
    JZ2440开发笔记(9)——位置无关代码设计【转】
    JZ2440开发笔记(8)——FCLK、HCLK和PCLK
    JZ2440开发笔记(7)——2440启动方式
    JZ2440开发笔记(6)——存储控制器
    JZ2440开发笔记(5)——通过按键点亮LED
    JZ2440开发笔记(4)——设置静态IP
    JZ2440开发笔记(3)——配置TFTP
  • 原文地址:https://www.cnblogs.com/hbyer/p/10641317.html
Copyright © 2020-2023  润新知