传送门:https://jzoj.net/senior/#main/show/6001
比较简单的一道题
比较明显的思路是,如果
a
a
a地雷能引爆
b
b
b地雷,就连一条
a
→
b
a\rightarrow b
a→b的有向边,这样的话一个强连通分量中肯定选最小的
缩点后一个联通块肯定是选入度为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;
}