zoukankan      html  css  js  c++  java
  • P5443 [APIO2019]桥梁

    P5443 [APIO2019]桥梁

    P3247 [HNOI2016]最小公倍数很像。

    对于边来说同样是两维限制,但是时间轴已经自动有序。

    所以我们还是可以考虑分块。

    对于当前块内的询问,首先我们把所有在当前不需要改变的边存下来,然后对于每一个询问可以双指针扫描即可,对于当前块内的边,每次询问的时候暴力加入即可。

    使用可撤销并查集维护,时间复杂度 (O(nsqrt{n}logn))

    也可以优化,但是不怎么会。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
    	x=0;char ch=getchar();bool f=false;
    	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	x=f?-x:x;
    	return ;
    }
    template <typename T>
    inline void write(T x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    	return ;
    }
    const int N=5e5+5,M=1e6+5,Siz=1e3;
    int n,m,qq,fa[N],siz[N];
    struct edge{int from,to,val,id;}E[M];
    int Getfa(int x){return fa[x]==x?x:Getfa(fa[x]);}
    void Init(int n){
    	for(int i=1;i<=n;i++) fa[i]=i,siz[i]=1;
    	return ;
    }
    int belong[N];
    int lastx[M],lasty[M];//用于记录并查集之前状态,回滚时用 
    void Merge(int id){
    	int x=E[id].from;
    	int y=E[id].to;
    	int fx=Getfa(x),fy=Getfa(y);
    	if(fx!=fy){
    		if(siz[fx]>siz[fy]) swap(fx,fy);
    		lastx[id]=fx,lasty[id]=fy,fa[fx]=fy;
    		siz[fy]+=siz[fx];
    	} 
    }
    struct oper{int type,x,val;}q[N];
    struct Que{//询问 
    	int id,x,val;
    	Que(){}
    	Que(int _id,int _x,int _val){id=_id,x=_x,val=_val;}
    	friend bool operator < (Que p,Que q){return p.val>q.val;}
    };
    vector<Que>Q;
    struct update{//需要合并的边 
    	int id,val;
    	update(){}
    	update(int _id,int _val){id=_id;val=_val;}
    	friend bool operator < (update p,update q){return p.val>q.val;}
    };
    int ans[N];
    bool vis[N];//标记哪些边的边权需要修改 
    bool tmp[N];//标记当前块需要修改的边 
    vector<update>U1;//不需要修改,但是需要合并的边 
    vector<int>U2;//需要修改,需要合并的边 
    vector<int>back;//回滚用 
    void Rebuild(int last){
    	for(int i=1;i<=m;i++) U1.push_back(update(i,E[i].val)),lastx[i]=0;
    	Init(n);
    	sort(U1.begin(),U1.end());
    	sort(Q.begin(),Q.end());
    	for(int i=0,j=0;i<Q.size();i++){////遍历每个询问 
    		back.clear();
    		while(j<U1.size()&&U1[j].val>=Q[i].val){//双指针找出可以经过的边 
    			if(!vis[U1[j].id]) Merge(U1[j].id),lastx[U1[j].id]=0;//不需要回滚 
    			j++;
    		}
    		for(int p=last;p<Q[i].id;p++){
    			if(q[p].type==1) tmp[q[p].x]=1; 
    		} 
    		for(int p=0;p<U2.size();p++){//修改前边权比当前询问要大,
    		//由于在后续可能涉及修改,需要进行回滚 
    			if(!tmp[U2[p]]&&Q[i].val<=E[U2[p]].val){
    				Merge(U2[p]);
    				back.push_back(U2[p]); 
    			}
    		}
    		for(int p=Q[i].id;p>=last;p--){
    		//查询时序之前被修改了,并且修改后边权比当前查询负载要大
            //注意:只有修改后边权比当前查询大的边才会进行合并,所以通过from[s[p]]=-1在回撤时过滤掉不符合要求的边 
    			if(q[p].type==1) tmp[q[p].x]=0;//回滚tmp数组 
    			if(q[p].type==2||lastx[q[p].x]) continue;//跳过Que 
    			lastx[q[p].x]=-1;
    			back.push_back(q[p].x);
    			if(q[p].val>=Q[i].val) Merge(q[p].x);//如果修改后变得对答案有影响,就合并 
    		}
    		ans[Q[i].id]=siz[Getfa(Q[i].x)];
    		for(int p=back.size()-1;p>=0;p--){//回滚 
    			if(lastx[back[p]]!=-1){ 
    				siz[lasty[back[p]]]-=siz[lastx[back[p]]];
    				fa[lastx[back[p]]]=lastx[back[p]]; 
    			} 
    			lastx[back[p]]=0; 
    		}
    	}
    }
    int main(){
    	read(n),read(m);
    	for(int i=1;i<=m;i++) read(E[i].from),read(E[i].to),read(E[i].val),E[i].id=i;
    	read(qq);
    	for(int i=1;i<=qq;i++) belong[i]=i/Siz+1;
    	int last=1;
    	for(int i=1;i<=qq;i++){
    		read(q[i].type),read(q[i].x),read(q[i].val);
    		if(q[i].type==1){
    			if(!vis[q[i].x]) U2.push_back(q[i].x);
    			vis[q[i].x]=1;
    		}
    		else Q.push_back(Que(i,q[i].x,q[i].val));			
    		if(belong[i]!=belong[i+1]){
    			//存满一个块,进行一次离线操作
    			Rebuild(last);
    			while(last<=i){//last记录修改和查询到哪里 
    				vis[q[last].x]=0; 
    				if(q[last].type==1) E[q[last].x].val=q[last].val;
    				else write(ans[last]),putchar('
    ');
    				last++;
    			}
    			U1.clear(),U2.clear(),Q.clear(),back.clear();
    		}
    	}
    	return 0;
    } 
    
  • 相关阅读:
    史上最刁钻的十道英语面试题
    99%的人连Where are you from都不会回答?
    库存管理与订单的控制
    订单处理逻辑
    配送规划
    多商家电子商务解决方案
    电商库存规划
    库存管理从入门到精通
    商家报名系统
    经销商管理
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14665965.html
Copyright © 2011-2022 走看看