• LOJ#3145. 「APIO2019」桥梁 分块+可撤销并查集


    看到这道题时没有什么思路,只会打暴力,而且数据范围比较有迷惑性,那基本就是分块了.
    现在有两个暴力:
    1.每次 $O(1)$ 更新边权,然后 $O(m)$ 暴力查询一个点的答案.
    2.每次将所有边排序,然后 $O(1)/O(log n)$ 查询点权
    上述两种做法中查询与更新的时间复杂度很不平衡,所以考虑对操作进行分块来维持平衡.
    令每一个块的大小为 $B$,将 $B$ 中所有询问按照限制重量由大到小排序.
    对于所有未出现在 $B$ 中的边也按照边权从大到小排序.
    假设 $B$ 中没有修改的话我们可以在 $O(frac{m}{B} m)$ 的复杂度解决该问题.
    而 $B$ 中的修改我们就暴力更新就行,平均下来一个询问要修改 $O(B)$ 次.
    那么时间复杂度就是 $O(frac{m}{B}m log m+Q B log m)$.
    这个 $B$ 取大一点效果比较好,这里取到了 $700.$

    #include <cstdio>
    #include <stack>
    #include <vector>
    #include <cstring>
    #include <algorithm>  
    #define N 100004    
    #define M 200009 
    #define ll long long 
    #define pb push_back  
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;
    const int B=800;  
    int n,m,Q;     
    int id[N],ans[M],mark[M],vis[M];      
    struct Edge { 
        int u,v,c;  
        Edge(int u=0,int v=0,int c=0):u(u),v(v),c(c){}      
        bool operator<(const Edge b) const { 
            return c>b.c;  
        }
    }e[M],f[M];    
    struct OPT { 
        int ty,x,y,ti;   
        OPT(int ty=0,int x=0,int y=0,int ti=0):ty(ty),x(x),y(y),ti(ti){}     
        // 优先处理限重更大的   
        bool operator<(const OPT b) const { 
            return y>b.y;  
        }
    }a[M],g[M];   
    struct UFS {       
        int size[N],p[N];    
        void init() { 
            for(int i=1;i<N;++i) { 
                size[i]=1,p[i]=i;  
            }
        }     
        int find(int x) {   
            return p[x]==x?x:find(p[x]);   
        }
        void ADD(int x,int y) {      
            x=find(x),y=find(y);  
            // 合并 x 与 y     
            if(x==y) {  
                return;  
            }
            if(size[x]>size[y]) {   
                swap(x,y); 
            } 
            // 将 x 合并到 y 上      
            size[y]+=size[x],p[x]=y;     
        }   
        struct DEL {    
            int x,y;  
            DEL(int x=0,int y=0):x(x),y(y){}  
        };  
        stack<DEL>v;   
        void TEM(int x,int y) { 
            x=find(x),y=find(y);      
            if(x==y) return; 
            if(size[x]>size[y]) {   
                swap(x,y); 
            } 
            size[y]+=size[x],p[x]=y;  
            v.push(DEL(x,y));  
        }       
        int Query(int x) {  
            x=find(x); 
            return size[x];  
        }
        void CLR() {        
            while(!v.empty()) {  
                DEL cur=v.top(); v.pop();  
                size[cur.y]-=size[cur.x];         
                p[cur.x]=cur.x;  
            }
        }   
    }T;   
    void calc(int cur) { 
        // 当前位置为 cur  
        int cnt=0,c2=0;
        for(int i=cur;i<=Q;++i) {   
            if(id[i]!=id[cur]) break;   
            if(a[i].ty==1) mark[a[i].x]=cur;       
            else g[++c2]=a[i],g[c2].ti=i;      
        }   
        for(int i=1;i<=m;++i) { 
        	vis[i]=0;    
            if(mark[i]==cur) continue;   
            f[++cnt]=e[i];    
        }    
        sort(g+1,g+1+c2); 
        sort(f+1,f+1+cnt);  
        T.init(); 
        for(int i=1,j=1;i<=c2;++i) {   
            while(j<=cnt&&f[j].c>=g[i].y) {    
                T.ADD(f[j].u,f[j].v);  
                ++j;  
            }
            for(int k=cur;k<=Q;++k) { 
                if(id[k]!=id[cur]) break;  
                if(a[k].ty==1) vis[a[k].x]=0;   
            }
            for(int k=g[i].ti-1;k>=cur;--k) {   
                if(a[k].ty==1&&!vis[a[k].x]&&a[k].y>=g[i].y) {    
                    vis[a[k].x]=1;  
                    T.TEM(e[a[k].x].u,e[a[k].x].v);  
                }   
                if(a[k].ty==1) vis[a[k].x]=1;       
            }
            for(int k=g[i].ti+1;k<=Q;++k) {
            	if(id[k]!=id[cur]) break;    
            	if(a[k].ty==1&&!vis[a[k].x]&&e[a[k].x].c>=g[i].y) {
            		T.TEM(e[a[k].x].u,e[a[k].x].v);   
            	}
            }
            // 处理完贡献了,可以查询   
            ans[g[i].ti]=T.Query(g[i].x);    
            T.CLR();   
        }   
        for(int i=cur;i<=Q;++i) { 
            if(id[i]!=id[cur]) break;   
            if(a[i].ty==1) {    
                e[a[i].x].c=a[i].y;    
            }    
        }    
    }
    int main() { 
        // setIO("input");  
        int x,y,z;     
        scanf("%d%d",&n,&m);  
        for(int i=1;i<=m;++i) { 
            scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].c);   
        }   
        scanf("%d",&Q);    
        // ty=1, w(x)->y    
        // ty=2, s(x)->y        
        for(int i=1;i<=Q;++i) { 
            id[i]=(i-1)/B+1;            
            scanf("%d%d%d",&a[i].ty,&a[i].x,&a[i].y);            
        }        
        for(int i=1;i<=Q;++i) { 
            if(id[i]!=id[i-1]) {   
                calc(i); 
            }  
        }
        for(int i=1;i<=Q;++i) {     
            if(a[i].ty==2) printf("%d
    ",ans[i]);  
        }   
        return 0; 
    }
    

      

  • 相关阅读:
    自定义博客园skin
    c++11: <thread>学习
    《明日方舟》Python版公开招募工具
    Python列表
    Python基础
    C#常用修饰符
    C#单例类的实现
    云服务器反黑客入侵攻防实录(一)
    在CentOS7.6上安装自动化运维工具Ansible以及playbook案例实操
    技术漫谈 | 远程访问和控制云端K8S服务器的方法
  • 原文地址:https://www.cnblogs.com/guangheli/p/13492811.html
Copyright © 2020-2023  润新知