题意:
分析:
- 暴力
-
按题目模拟,对于每一个询问操作,用并查集维护满足题意的边,求查询点所在连通块大小,复杂度 (O(qmalpha))
-
给询问排序,按重量降序,每次把满足要求的未被修改的边加入并查集,暴力枚举合法的修改操作,可撤销并查集维护,复杂度 (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;
}