JZOJ6001【THUWC2019模拟2019.1.16】Mines(强连通分量缩点,人工栈,线段树优化建图)

4 篇文章 0 订阅
3 篇文章 0 订阅

传送门:https://jzoj.net/senior/#main/show/6001


比较简单的一道题
比较明显的思路是,如果 a a a地雷能引爆 b b b地雷,就连一条 a → b a\rightarrow b ab的有向边,这样的话一个强连通分量中肯定选最小的
缩点后一个联通块肯定是选入度为0的点

再用 s e t set set维护修改

用线段树优化建图
(这题会爆栈,最好写个人工栈

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x],y = e[i].y;i;i = e[i].n,y = e[i].y)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
#define ls (rt<<1)
#define rs (rt<<1|1)
int rd()
{
    int num = 0;char c = getchar();bool flag = true;
    while(c < '0'||c > '9') {if(c == '-') flag = false;c = getchar();}
    while(c >= '0' && c <= '9') num = num*10+c-48,c = getchar();
    if(flag) return num;else return -num;
}
const int INF = 2e9;
int n,Q;
int linkk[501000],t;
int dfn[501000],low[501000],tot,du[501000],g[501000];
int bel[501000],cor;
int v[501000];
bool f[501000];
ll ans;
int st[501000],top;
multiset<int>h[501000];
int tmp[501000],tt;
int N,id[501000];
int res,cas;
struct ndoe{int n,x,y;}e[5001000];
struct point{int p,r,c;}a[500100];
bool mycmp(point x,point y){return x.p < y.p;}
void insert(int x,int y){e[++t].y = y;e[t].x = x;e[t].n = linkk[x];linkk[x] = t;}
int fk[501000],fr[501000],cur[501000];
void tarjan(int rt)
{
	fk[++fk[0]] = rt;
	loop:;
	
	int x = fk[fk[0]];
	if(!dfn[x]) 
	{
		dfn[x] = low[x] = ++tot;
		f[x] = true;st[++top] = x;
    }
	for(int i = cur[x];i;cur[x] = i = e[i].n)
	{
		int y = e[i].y;
		if(!dfn[y])
		{
			fk[++fk[0]] = y; fr[y] = x; cur[x] = e[i].n;
			goto loop;
		}
		else if(f[y]) low[x] = min(low[x],dfn[y]);
	}
	if(dfn[x] == low[x])
	{
		cor++;v[cor] = INF;
		while(st[top] != x)
		{
			f[st[top]] = false;
			bel[st[top]] = cor;
			if(st[top] <= n)
			{
				v[cor] = min(v[cor],a[st[top]].c);
				h[cor].insert(a[st[top]].c);
			}
			top--;
		}
		f[x] = false;bel[x] = cor;
		if(x <= n)
		{
			v[cor] = min(v[cor],a[x].c);
			h[cor].insert(a[x].c);
		}
		top--;
	}
	fk[0]--;
	if(fk[0]) {low[fk[fk[0]]] = min(low[fk[fk[0]]],low[x]);goto loop;}
}

void build(int rt,int l,int r)
{
	if(l == r) {N = max(N,rt+n);id[l] = rt;return;}
	else insert(rt+n,ls+n),insert(rt+n,rs+n);
	int mid = (l+r)>>1;
	build(ls,l,mid);build(rs,mid+1,r);
}
void update(int rt,int l,int r,int x,int y,int id)
{
	if(x <= l && r <= y) {insert(id,rt+n);return;}
	if(l > y || r < x) return;
	int mid = (l+r)>>1;
	update(ls,l,mid,x,y,id);
	update(rs,mid+1,r,x,y,id);
}
void makenode()
{
	rep(i,1,n)
	{
		int l = a[i].p - a[i].r,r = a[i].p + a[i].r;
		l = lower_bound(tmp+1,tmp+tt+1,l) - tmp;
		r = upper_bound(tmp+1,tmp+tt+1,r) - tmp;
		r--;
		update(1,1,tt,l,r,i);
	}
	build(1,1,tt);
	rep(i,1,n) insert(id[lower_bound(tmp+1,tmp+tt+1,a[i].p) - tmp]+n,i);
}
void pre()
{
	rep(i,1,n) tmp[i] = a[i].p;
	sort(tmp+1,tmp+n+1);
	tt = unique(tmp+1,tmp+n+1) - tmp - 1;
	makenode();
	rep(i,1,N) cur[i] = linkk[i];
	rep(i,1,N) if(!dfn[i]) tarjan(i);
	int T = t;
	t = 0;memset(linkk,0,sizeof(linkk));
    rep(i,1,T)
    {
    	int x = e[i].x,y = e[i].y;
    	if(bel[x] != bel[y]) insert(bel[x],bel[y]),du[bel[y]]++;
	}
}
int q[501000],head,tail;
void topwork()
{
	head=1;tail=0;
	rep(i,1,cor) if(du[i] == 0) q[++tail] = i;
	rep(i,1,cor) g[i] = (int)h[i].size()>0;
	while(head<=tail)
	{
		int x = q[head++];
		if(g[x] == 1 && (int)h[x].size()>0) f[x] = true;
		for(int i = linkk[x];i;i = e[i].n)
		{
			int y = e[i].y;
			g[y] += g[x];
			du[y]--;
			if(du[y] == 0) q[++tail] = y;
		}
	}
}
int main()
{
	freopen("mines.in","r",stdin);
    freopen("mines.out","w",stdout);
	n = rd();Q = rd();
	rep(i,1,n) a[i].p = rd(),a[i].r = rd(),a[i].c = rd();
	pre();
	rep(i,1,cor) f[i] = false;
	topwork();
	rep(i,1,cor) if(!f[i]) f[i] = g[i] == 0 && ((int)h[i].size()>0);
	             else if((int)h[i].size()==0) f[i] = false;
	rep(i,1,cor) ans += f[i]?v[i]:0;
	rep(i,1,Q)
	{
		int x = rd(),y = rd();
		if(!f[bel[x]]) {printf("%lld\n",ans);continue;}
		ans -= v[bel[x]];
		h[bel[x]].erase(h[bel[x]].lower_bound(a[x].c));
		a[x].c = y;
		h[bel[x]].insert(a[x].c);
		
		v[bel[x]] = *h[bel[x]].begin();
		ans += v[bel[x]];
		printf("%lld\n",ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值