Codeforces Round 1067 (Div. 2) E Sink

事实上这题只需要维护每个极大连通块是局部最小值的数量。
事实上这个可以等价于每个点是局部最小值的数量的和。
直接维护即可,答案为0的个数。
注意维护技巧,修改的点可以看作独立的点,原来的答案如果其 size 为 0 就不考虑其的贡献,也就是 ans-- 。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using std::cin,std::cout;
const int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
const int N=600020;
int n,m;
std::vector<int>a[N],b[N];
int f[N],val[N],si[N];
int find(int x){
    while(x!=f[x])x=f[x]=f[f[x]];
    return x;
}
int ans;
void merge(int x,int y){
    if(!x||!y)return ;
    x=find(x),y=find(y);
    if(x==y)return ;
    if(val[y]==0)ans--;
    f[x]=y,val[y]+=val[x];
    if(val[x]==0)ans--;
    if(val[y]==0)ans++;
    si[y]+=si[x];
}
void del(int x){
    x=find(x);
    val[x]--;
    if(val[x]==0)ans++;
}
void add(int x){
    x=find(x);
    if(val[x]==0)ans--;
    val[x]++;
}
void go(int x,int y,int t){
    for(int d=0;d<4;d++){
        int nx=x+dx[d],ny=y+dy[d];
        if(nx<=0||nx>n||ny<=0||ny>m)continue;
        if(a[nx][ny]<a[x][y]){
            if(t==1)add(b[x][y]);else del(b[x][y]);
        }
        if(a[nx][ny]>a[x][y]){
            if(t==1)add(b[nx][ny]);else del(b[nx][ny]);
        }
    }
    if(t==1){
        for(int d=0;d<4;d++){
            int nx=x+dx[d],ny=y+dy[d];
            if(nx<=0||nx>n||ny<=0||ny>m)continue;
            if(a[nx][ny]==a[x][y]){
                // if(t==1)add(b[x][y]);else del(b[x][y]);
                merge(b[nx][ny],b[x][y]);
                // cout<<nx<<" "<<ny<<" "<<x<<" "<<y<<"\n";
            }
        }
    }
}
void work(){
    int tot=0;
    cin>>n>>m;
    for(int i=0;i<=n+1;i++){
        a[i].clear(),b[i].clear();
        a[i].resize(m+1),b[i].resize(m+1);
    }
    ans=0;
    ans=n*m;
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
        tot++;
        f[tot]=tot,b[i][j]=tot,val[tot]=0;
        si[tot]=1;
        go(i,j,-1);
        cin>>a[i][j];
        go(i,j,1);
        // cout<<ans<<"===\n";
    }
    cout<<ans<<'\n';
    int q;
    cin>>q;
    while(q--){
        int x,y,c;
        cin>>x>>y>>c;
        go(x,y,-1);
        a[x][y]-=c;
        si[find(b[x][y])]--;
        if(si[find(b[x][y])]==0)ans--;
        tot++;
        b[x][y]=tot;
        f[tot]=tot;
        val[tot]=0;
        si[tot]=1;
        ans++;
        go(x,y,1);
        cout<<ans<<'\n';
    }
}
int main(){
    // std::ios::sync_with_stdio(0);
    // cin.tie(0),cout.tie(0);
    int t=1;
    cin>>t;
    while(t--){
        work();
    }
    return 0;
}
posted @ 2025-12-18 23:52  Qzong  阅读(3)  评论(0)    收藏  举报