「APIO 2019」桥梁

题目链接

「APIO 2019」桥梁

题目描述

你现在有一个n个点,m条边的一张图,每条边有一个重量限制 l i m i lim_{i} limi表示只有重量不大于 l i m i lim_{i} limi的货车才能通过这条边,现在有两种类型的操作,一种是修改边的限制,一种是询问载重为 w i w_{i} wi的货车,从 s i s_{i} si点出发能到多少个不同的点(包括 s i s_{i} si

题目分析

我们考虑对时间分块,对于每一块内,我们把边分成两类,一类是有修改的边,一类是没有修改的边,我们把没有修改的边直接用并查集维护即可,有修改的边我们对于每一个询问操作直接暴力判断,然后再撤销即可
我们分析一下时间复杂度,设块的大小为B
O ( Q B B 2 + Q B m l o g m ) O(\frac{Q}{B}B^2+\frac{Q}{B}mlogm) O(BQB2+BQmlogm)
均值一下取 B = m l o g m B=\sqrt {mlogm} B=mlogm
注意判一下n,m极小的时候

#include<bits/stdc++.h>
#define pii pair<int,int>
#define pb(x) push_back(x)
#define mk(x,y) make_pair(x,y)
#define RG register 
using namespace std;
const int N=1e5+10;
struct node{
	int u,v,lim,time,id;
	node(int x=0,int y=0,int z=0,int e=0,int r=0){
		u=x; v=y; lim=z; time=e; id=r;
	}
};
struct ques{
	int x,w,time;
	ques(int xx=0,int y=0,int z=0){
		x=xx; w=y; time=z;
	}
};
template<class T>void read(T &x){
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9')  {f|=(ch=='-');ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return;
}
ques qd[N<<2];
node ld[N<<2],lb[N<<2];
int fa[N],sz[N],ans[N],u[N],v[N],opt[N],w[N],x[N],y[N];
bool b[N];
int n,m,q;
vector<pii>p;
int getfather(int x){while (fa[x]!=x) x=fa[x]; return x;}
void merge(int x,int y,int z){
//	cout << x << ' ' << y << endl;
	x=getfather(x); y=getfather(y);
//	cout << x << ' ' << y << endl;
	if (x!=y) {
	if (sz[x]<sz[y]) {fa[x]=y,sz[y]+=sz[x]; if (z) p.pb(mk(x,y));} else {fa[y]=x,sz[x]+=sz[y]; if (z) p.pb(mk(y,x));}
	}
}
void cancel(int x,int y){
	fa[x]=x; sz[y]-=sz[x];
}
bool cmp(ques x,ques y){
	return x.w>y.w;
}
bool cmp1(node x,node y){
	return x.lim<y.lim;
}
bool cmp2(node x,node y){
	return x.time>y.time;
}
void solve(int l,int r){
	for (RG int i=1;i<=n;i++) fa[i]=i,sz[i]=1;
	for (RG int i=1;i<=m;i++) b[i]=0;
	int sum1=0,sum2=0,sum3=0;
	for (RG int i=l;i<=r;i++) 
		if (opt[i]==1) {
		b[x[i]]=1; ld[++sum1]=node(u[x[i]],v[x[i]],y[i],i,x[i]); 
		} else {
		qd[++sum2]=ques(x[i],y[i],i);
//		cout << qd[0].id << endl;
		}
	for (RG int i=1;i<=m;i++) if (!b[i]) lb[++sum3]=node(u[i],v[i],w[i],i,i); else ld[++sum1]=node(u[i],v[i],w[i],0,i);
	sort(qd+1,qd+sum2+1,cmp);
	sort(lb+1,lb+sum3+1,cmp1);	
	sort(ld+1,ld+sum1+1,cmp2);
	for (RG int i=1;i<=sum2;i++) {
		while (sum3&&lb[sum3].lim>=qd[i].w) merge(lb[sum3].u,lb[sum3].v,0),sum3--;
		for (RG int j=1;j<=sum1;j++) {
		 if (ld[j].time<=qd[i].time&&ld[j].lim>=qd[i].w&&b[ld[j].id]) merge(ld[j].u,ld[j].v,1);
		 if (ld[j].time<=qd[i].time) b[ld[j].id]=0;
		 }
		for (RG int j=1;j<=sum1;j++) b[ld[j].id]=1;
		ans[qd[i].time]=sz[getfather(qd[i].x)]; 
//		cout << "YES" << endl;
		while (!p.empty()) cancel(p[p.size()-1].first,p[p.size()-1].second),p.pop_back(); 
	}
	for (RG int j=1;j<=sum1;j++) if (b[ld[j].id]) w[ld[j].id]=ld[j].lim,b[ld[j].id]=0;  
}
int main(){
	read(n); read(m);
	for (int i=1;i<=m;i++) read(u[i]),read(v[i]),read(w[i]);
	read(q);
	int block=ceil(sqrt(max(m,q)*log2(max(n,q))));
	for (int i=1;i<=q;i++) read(opt[i]),read(x[i]),read(y[i]);
	int sum=(q%block==0?q/block:q/block+1);
	for (int i=1;i<=sum;i++) {
		int l=(i-1)*block+1,r=min(i*block,q);
		solve(l,r);
	}
	for (int i=1;i<=q;i++) if (opt[i]==2) printf("%d\n",ans[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值