题目链接
「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]);
}