思路:考试的时候打了LCT,自以为能过,没想到只能过80..
考完一想:lct的做法点数是100W,就算是nlogn也会T。
讲一下lct的做法把:首先如果一条边连接的两个点都在同一个联通块内,那么这条边对答案没有影响,可以忽略,因此,问题变成了每次询问两个点中路径上权值最大的边(这里的权值我们令它为加入这条边的时间),边我们用一个点连接两个端点来表示。
正解:由于是无根树,因此我们用并查集按秩合并,每次把小的加到大的里面去,询问的时候暴力走lct查找最大即可。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 int fa[500005],n,m,size[500005],ty[500005],vis[500005],vistag; 7 int read(){ 8 int t=0,f=1;char ch=getchar(); 9 while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();} 10 while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} 11 return t*f; 12 } 13 int find(int x){ 14 if (fa[x]==x) return x; 15 else return fa[x]=find(fa[x]); 16 } 17 int main(){ 18 n=read();m=read(); 19 for (int i=1;i<=n;i++) fa[i]=size[i]=1,ty[i]=0; 20 int Case=0,lastans=0; 21 for (int i=1;i<=m;i++){ 22 int opt=read(),u=read()^lastans,v=read()^lastans; 23 if (!opt){ 24 ++Case; 25 u=find(u),v=find(v); 26 if (u!=v){ 27 if (size[u]>size[v]) std::swap(u,v); 28 fa[u]=v; 29 size[v]+=size[u]; 30 ty[u]=Case; 31 }else{ 32 ++vistag; 33 int fu=u,fv=v; 34 for (;;u=fa[u]){ 35 vis[u]=vistag; 36 if (fa[u]==u) break; 37 } 38 int lca=0; 39 for (;;v=fa[v]){ 40 if (vis[v]==vistag&&!lca) lca=v; 41 if (fa[v]==v) break; 42 } 43 if (u!=v){ 44 printf("%d ",lastans=0); 45 continue; 46 }else{ 47 int ans=0; 48 for (;fu!=lca;fu=fa[fu]) ans=std::max(ans,ty[fu]); 49 for (;fv!=lca;fv=fa[fv]) ans=std::max(ans,ty[fv]); 50 printf("%d ",lastans=ans); 51 } 52 } 53 } 54 } 55 }