P11287 [COTS 2017] 影响 Utjecaj 题解

思路:

注:分析默认 \(n\)\(m\)\(q\) 同阶。

假设从图中删去关键节点,那么图将被划分成若干个联通块。如果有关键点与联通块相连,那么这个联通块内的点都是可达的。

所以考虑将联通块打包,缩成一个点,断开关键节点之间的边。

那么一个点的影响力就是所有与之直接相连的点和自身的权值之和。

那么问题转化为了:

  1. 对点 \(x\) 和直接相连的点加上一个值。
  2. 查询点 \(x\) 和直接相连的点的权值和。

直接做是 \(O(n\sum deg_i)\)\(deg_i\) 是点 \(i\) 的出度。

考虑根号分治。我们设立一个阈值 \(B\),初始时先将点 \(x\) 和直接相连的点的权值和预处理出来。对于修改操作,若 \(deg_x\le B\),直接暴力修改,反之,我们对 \(x\) 打上标记。询问时,我们再在权值和的基础加上与 \(x\) 相连的且出度 \(>B\) 的点上的标记。修改操作是 \(O(B)\),而对于询问, 默认 \(\sum deg_i \le 2\times n\), 那么出度 \(> B\) 的点不超过 \({n}\over B\),询问复杂度为 \(O({n\over B})\)

\(B\)\(\sqrt n\) 时复杂度最优,为 \(O(n\sqrt n)\)

code

#include<bits/stdc++.h>
#define all(x) x.begin(),x.end()
#define mset(x,y) memset((x),(y),sizeof((x)))
#define mcpy(x,y) memcpy((x),(y),sizeof((y)))
#define FileIn(x) freopen(""#x".in","r",stdin)
#define FileOut(x) freopen(""#x".out","w",stdout)
#define debug(x) cerr<<""#x" = "<<(x)<<'\n'
#define Assert(x) if(!(x)) cerr<<"Failed: "#x" at line "<<__LINE__,exit(1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 Int;
const int N=2e5+10,B=400;
bool StM;
int c[N],a[N],n,m,k,q;
int in[N],Be[N];
ll b[N],sum[N],tag[N];
vector<int>G[N],E[N],H[N],Fa[N];
map<int,bool>Cenect[N];
map<pair<int,int>,bool>edge;
void dfs(int now)
{
    Be[now]=k,b[k]+=a[now];
    for(int to:E[now])
        if(!Be[to]) dfs(to);
    return;
}
void Main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>c[i];
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1,x,y;i<=m;i++)
    {
        cin>>x>>y;
        if(x>y) swap(x,y);
        if(edge.count({x,y})) continue;
        edge[{x,y}]=1;
        G[x].push_back(y);
        G[y].push_back(x);
        if(c[x]|c[y]) continue;
        E[x].push_back(y);
        E[y].push_back(x);
    }
    for(int i=1;i<=n;i++)
        if(!Be[i]) ++k,dfs(i);
    for(int now=1;now<=n;now++)
    {
        if(c[now]){
            for(int to:G[now])
                if(Be[to]^Be[now]&&!c[to])
                {
                    if(Cenect[Be[now]].count(Be[to])) continue;
                    H[Be[now]].push_back(Be[to]),++in[Be[to]];
                    Cenect[Be[now]][Be[to]]=1;
                } 
        }
        else{
            for(int to:G[now])
                if(Be[to]^Be[now])
                {
                    if(Cenect[Be[now]].count(Be[to])) continue;
                    H[Be[now]].push_back(Be[to]),++in[Be[to]];
                    Cenect[Be[now]][Be[to]]=1;
                }
        }
    }
    for(int now=1;now<=k;now++)
    {
        sum[now]=b[now];
        for(int to:H[now]) sum[now]+=b[to];
        if(in[now]>B)
            for(int to:H[now]) Fa[to].push_back(now);
    }
    cin>>q;
    int op,x,y,now;
    while(q--)
    {
        cin>>op>>x;
        if(op==1){
            cin>>y;now=Be[x];
            int val=y-a[x];
            a[x]=y,b[now]+=val,sum[now]+=val;
            if(in[now]>B)
                tag[now]+=val;
            else for(int to:H[now]) sum[to]+=val;
        }
        else{
            ll delta=0;now=Be[x];
            for(int to:Fa[now])
                delta+=tag[to];
            cout<<sum[now]+delta<<'\n';
        }
    }
}
bool EdM;
int main()
{
    cerr<<fabs(&StM-&EdM)/1024.0/1024.0<<" MB\n";
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int StT=clock();
    int T=1;
    while(T--) Main();
    int EdT=clock();
    cerr<<1e3*(EdT-StT)/CLOCKS_PER_SEC<<" ms\n";
    return 0;
}
posted @ 2024-11-20 12:06  EityDawn  阅读(25)  评论(0)    收藏  举报