P5443 [APIO2019]桥梁 操作分块+可撤销并查集

题意:

戳这里

分析:

  • 暴力
  1. 按题目模拟,对于每一个询问操作,用并查集维护满足题意的边,求查询点所在连通块大小,复杂度 (O(qmalpha))

  2. 给询问排序,按重量降序,每次把满足要求的未被修改的边加入并查集,暴力枚举合法的修改操作,可撤销并查集维护,复杂度 (O(q^2log)))

  • 正解

两种暴力的瓶颈分别在于,一个枚举了所有的边,一个枚举了所有的操作

那么考虑怎么均摊两个复杂度

分块 txdy

(block) 个操作分成一个块,对于每一个块内按照第二种暴力,对询问进行排序修改,然后处理完一个块内的询问后,把所有的修改操作加上

这样每次查询时,枚举的被修改的边最多只有 (s) 个,所以一个块内的复杂度不超过(O(s^2alpha))

总的复杂度不超过(O(q imes s imes alpha(块内的查询)+frac{q imes m log m}{s}(每个块的预处理)))

代码:

#include<bits/stdc++.h>

using namespace std;

namespace zzc
{
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }

    const int maxn = 1e5+5;
    const int blo = 1024;
    int n,qt,cnt,top,m;
    int st[maxn],ans[maxn],fa[maxn],siz[maxn],id[maxn],vis[maxn];

    struct edge
    {
        int frm,to,val,id;
        bool operator <(const edge &b)const
        {
        	return val>b.val;
		}
    }e[maxn<<1];
    
    struct query
    {
        int pos,w,tim;
        query(){}
        query(int pos,int w,int tim):pos(pos),w(w),tim(tim){}
        bool operator <(const query &b)const
        {
        	return w>b.w;
		}
    };
    vector<query> q1,q2,tmp;
    
    int find(int x){return fa[x]==x?x:find(fa[x]);}

    void merge(int x,int y)
    {
        int fx=find(x),fy=find(y);
        if(fx!=fy)
        {
            if(siz[fx]<siz[fy]) swap(fx,fy);
            fa[fy]=fx;
            siz[fx]+=siz[fy];
            st[++top]=fy;
        }
    }

    void del(int num)
    {
        while(top>num)
        {
            int tmp=st[top--];
            siz[fa[tmp]]-=siz[tmp];
            fa[tmp]=tmp;
        }
    }

    void solve()
    {
        tmp.clear();top=0;
        sort(e+1,e+m+1);
        sort(q2.begin(),q2.end());
        for(int i=1;i<=m;i++) id[e[i].id]=i;//¸øÅÅÐòºóµÄ±ßÖرêºÅ 
        for(int i=1;i<=n;i++) siz[i]=1,fa[i]=i;
        
        for(auto it:q1) vis[it.pos]=-1,tmp.push_back(query(it.pos,e[id[it.pos]].val,0));//°Ñеıßtim ÉèΪ0£¬ÕâÑùÿ´Î¿ÉÒÔ½«Ö®Ç°visµÄÓ°ÏìÏûµô 
        for(auto it:q1) tmp.push_back(it);
        
        for(int i=0,it=1;i<(int)q2.size();i++)
        {
            while(it<=m&&e[it].val>=q2[i].w)
            {
                if(!vis[e[it].id]) merge(e[it].frm,e[it].to);
                it++;
            }
            int lst=top;
            
            for(auto x:tmp) if(x.tim<=q2[i].tim) vis[x.pos]=x.w;
            for(auto x:q1) if(vis[x.pos]>=q2[i].w) merge(e[id[x.pos]].frm,e[id[x.pos]].to);//½«·ûºÏÒªÇóµÄ±ß¼ÓÈë²¢²é¼¯ 
            
            ans[q2[i].tim]=siz[find(q2[i].pos)];
            del(lst);
        }
		for(auto x:q1) e[id[x.pos]].val=x.w,vis[x.pos]=0;//°Ñ²Ù×÷µÄÓ°Ïì¼ÓÔØÉÏ 
		q1.clear();q2.clear();
    }

    void work()
    {
        int opt;
        query x;
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            e[i].frm=read();
            e[i].to=read();
            e[i].val=read();
            e[i].id=i;
        }
        qt=read();
        for(int i=1;i<=qt;i++)
        {
            opt=read();
            x.pos=read();x.w=read();x.tim=i;
            if(opt==1) q1.push_back(x);
            else q2.push_back(x);
            if(i%blo==0) solve();
        }
        if(qt%blo) solve();
        for(int i=1;i<=qt;i++) if(ans[i]) printf("%d
",ans[i]);
    }


}


int main()
{
    zzc::work();
    return 0;
}
原文地址:https://www.cnblogs.com/youth518/p/14179953.html