看了T2才知道今年供题是Russia。
有一次在CF上看到Um_nik和dls在讨论ICPC,当时听说国际比赛不敢出数据结构大题,甚至连码量大的题,或者计算机理论要求比较高的题都不敢出,因为不清楚哪些国家在某些套路上有什么偏好,做APIO的时候感觉无比真实。。。
但是这道题正解是不是太明显了一点,China肯定一堆人切了吧
可惜我没去APIO不然就200+了
第一感觉是线段树分治,但是仔细想了想没有办法维护连通块大小,如果是连通块个数就很好做。。。
看了下数据范围可能是根号分治,然后正解就真的是根号分治。
根号分治的话,要考虑两种暴力,修改少询问多,询问少修改多。
暴力一:修改暴力,询问就每次把合法边加到并查集里面看siz就行了。
暴力二:首先把没有修改过的边拿出来,按照 d d d排序,把询问拿出来,按照 d d d排序,然后顺序处理,没有修改的边直接加到并查集里面即可,有修改的边拿出来,把这个询问之前的修改操作,然后看有哪些边能加到并查集里面去,需要可回退化并查集。
每根号个操作拿出来做一遍,然后把修改操作上去即可。
块大小需要设置成根号下面套一个log才能到达理论最优。
不过因为常数问题可以自己夹带私货,比如乘个0.8什么的
代码:
#include
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;T num;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int M=1e5+7,N=5e4+7,S=700,P=S+7;
struct Edge{int u,v,d,id;};
struct Query{int u,d,id;};
Edge E[M],E1[M],E2[P];
Query Q[P];
int n,m,q;
int op[M],a[M],b[M];
int d[M],ori[M],ans[M];
int fa[N],sz[N];
int *st[N],pr[N],tp;
bool vis[M];
inline int gf(int u){while(fa[u]>0)u=fa[u];return u;}
inline int gf_(int u){while(fa[u]>0&&fa[fa[u]]>0)u=fa[u]=fa[fa[u]];return fa[u]>0?fa[u]:u;}
inline void pack(int &u){st[++tp]=&u,pr[tp]=u;}
inline void merge(int u,int v){
u=gf_(u),v=gf_(v);if(u==v)return ;
if(fa[u]>fa[v])std::swap(u,v);
if(fa[v]==fa[u])--fa[u];
fa[v]=u,sz[u]+=sz[v];
}
inline void _merge(int u,int v){
u=gf(u),v=gf(v);if(u==v)return ;
if(fa[u]>fa[v])std::swap(u,v);
if(fa[v]==fa[u])pack(fa[u]),--fa[u];
pack(fa[v]);fa[v]=u;
pack(sz[u]);sz[u]+=sz[v];
}
inline void solve(int l,int r){
int t1=0,t2=0,q=0;
for(int re i=l;i<r;++i)
if(op[i]==1)vis[a[i]]=true;
else Q[q++]=(Query){a[i],b[i],i};
for(int re i=0;i<m;++i)
(vis[E[i].id]?E2[t2++]:E1[t1++])=E[i];
memset(fa,0,n+1<<2);
std::fill(sz,sz+n+1,1);
std::sort(Q,Q+q,[](cs Query &a,cs Query &b){
return a.d>b.d;
});
for(int re j=0,k=0;k<q;++k){
while(j<t1&&Q[k].d<=E1[j].d)
merge(E1[j].u,E1[j].v),++j;
for(int re i=l;i<Q[k].id;++i)
if(op[i]==1)d[a[i]]=b[i];
for(int re i=0;i<t2;++i)
if(Q[k].d<=d[E2[i].id])
_merge(E2[i].u,E2[i].v);
ans[Q[k].id]=sz[gf(Q[k].u)];
while(tp)*st[tp]=pr[tp],--tp;
for(int re i=l;i<Q[k].id;++i)
if(op[i]==1)d[a[i]]=ori[a[i]];
}
for(int re i=l;i<r;++i)
if(op[i]==1)vis[a[i]]=false,d[a[i]]=ori[a[i]]=b[i];
for(int re j=0;j<t2;++j)
E2[j].d=d[E2[j].id];
std::sort(E2,E2+t2,[](cs Edge &a,cs Edge &b){
return a.d>b.d;
});
std::merge(E1,E1+t1,E2,E2+t2,E,[](cs Edge &a,cs Edge &b){
return a.d>b.d;
});
}
signed main(){
#ifdef zxyoi
freopen("bridge.in","r",stdin);
#endif
n=gi(),m=gi();
for(int re i=1;i<=m;++i){
int u=gi(),v=gi();d[i]=ori[i]=gi();
E[i-1]=(Edge){u,v,d[i],i};
}q=gi();
for(int re i=0;i<q;++i)op[i]=gi(),a[i]=gi(),b[i]=gi();
std::sort(E,E+m,[](cs Edge &a,cs Edge &b){
return a.d>b.d;
});
for(int re i=0;i<q;i+=S)solve(i,std::min(i+S,q));
for(int re i=0;i<q;++i)if(op[i]==2)cout<<ans[i]<<"\n";
return 0;
}