在我的认知中,运行速度方面应该是 gp_hash_table > cc_hash_table > unordered_map
但是在此题中我尝试使用 gp_hash_table
提速,却发现 cc_hash_table > unordered_map > gp_hash_table
甚至几个 unordered_map
只需要跑 200 ms 的点 gp_hash_table
都 T 飞了,这是为什么?
以下是使用 cc_hash_table
的代码,其余的只需要略微修改:
#include<bits/stdc++.h>
#include<bits/extc++.h>
#define inf 1e18
#define int long long
using namespace std;
using namespace __gnu_pbds;
const int N=100010,lgN=50;
inline int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
//树剖
struct SegementTree1{//这个是求dis用的树剖线段树
int w[N<<2];
inline void update(int u,int l,int r,int x,int k){
if(l==r){
w[u]=k;
return;
}
int mid=(l+r)>>1;
if(x<=mid)update(u*2,l,mid,x,k);
else update(u*2+1,mid+1,r,x,k);
w[u]=w[u*2]+w[u*2+1];
}
inline int query(int u,int l,int r,int x,int y){
if(x<=l&&r<=y)return w[u];
int mid=(l+r)>>1;
int res=0;
if(x<=mid)res+=query(u*2,l,mid,x,y);
if(y>mid)res+=query(u*2+1,mid+1,r,x,y);
return res;
}
}T1;
struct zyx{int to,w;};
vector<zyx> e[N];
struct csq{int u,v,w;};
vector<csq> edge;
int n,Q,cnt;
int fa[N],sz[N],dep[N],son[N],top[N],dfn[N],rnk[N];
inline void dfs1(int now,int fz){
fa[now]=fz;
sz[now]=1;
dep[now]=dep[fz]+1;
for(int i=0;i<(int)e[now].size();i++){
int to=e[now][i].to;
if(to==fz)continue;
dfs1(to,now);
sz[now]+=sz[to];
if(sz[to]>sz[son[now]])son[now]=to;
}
}
inline void dfs2(int now,int topf){
top[now]=topf;
dfn[now]=++cnt;
rnk[cnt]=now;
if(!son[now])return;
dfs2(son[now],topf);
for(int i=0;i<(int)e[now].size();i++){
int to=e[now][i].to;
if(to==fa[now]||to==son[now])continue;
dfs2(to,to);
}
}
int getdis(int x,int y){
int res=0;
while(top[x]!=top[y]){
if(dep[top[y]]>dep[top[x]])swap(x,y);
res+=T1.query(1,1,n,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
if(dep[y]>dep[x])swap(x,y);
res+=T1.query(1,1,n,dfn[y]+1,dfn[x]);
return res;
}
//树剖
//建点分树
struct SegementTree2{
int w[N*lgN],ls[N*lgN],rs[N*lgN],lazy[N*lgN];
int rt[N],tot;
inline void pushdown(int u){
if(!lazy[u])return;
w[ls[u]]+=lazy[u];
w[rs[u]]+=lazy[u];
lazy[ls[u]]+=lazy[u];
lazy[rs[u]]+=lazy[u];
lazy[u]=0;
}
inline void update1(int &u,int l,int r,int x,int k){//单点修改
if(!u)u=++tot;
if(l==r){
w[u]=k;
return;
}
int mid=(l+r)>>1;
pushdown(u);
if(x<=mid)update1(ls[u],l,mid,x,k);
else update1(rs[u],mid+1,r,x,k);
w[u]=min(w[ls[u]],w[rs[u]]);
}
inline void update2(int &u,int l,int r,int x,int y,int k){//区间加
if(!u)u=++tot;
if(x<=l&&r<=y){
w[u]+=k;
lazy[u]+=k;
return;
}
int mid=(l+r)>>1;
pushdown(u);
if(x<=mid)update2(ls[u],l,mid,x,y,k);
if(y>mid)update2(rs[u],mid+1,r,x,y,k);
w[u]=min(w[ls[u]],w[rs[u]]);
}
inline void build(int &u,int l,int r){
if(!u)u=++tot;
w[u]=inf;
if(l==r)return;
int mid=(l+r)>>1;
build(ls[u],l,mid);
build(rs[u],mid+1,r);
}
}T2;
int maxnson[N],vis[N],FA[N],sum,rt,dep2[N];
cc_hash_table<int,int> dfn2[N],sz2[N];
int tcnt;
inline void getrt(int now,int fz){
maxnson[now]=0;
sz[now]=1;
for(int i=0;i<(int)e[now].size();i++){
int to=e[now][i].to;
if(to==fz||vis[to])continue;
getrt(to,now);
sz[now]+=sz[to];
maxnson[now]=max(maxnson[now],sz[to]);
}
maxnson[now]=max(maxnson[now],sum-sz[now]);
if(maxnson[now]<maxnson[rt])rt=now;
}
inline void dfs(int from,int now,int fa){
dfn2[from][now]=++tcnt;//这里存一下每个点在以from为根的连通块中的dfn序与sz
sz2[from][now]=1;
for(int i=0;i<(int)e[now].size();i++){
int to=e[now][i].to;
if(to==fa||vis[to])continue;
dfs(from,to,now);
sz2[from][now]+=sz2[from][to];
}
}
inline void solve(int now){
vis[now]=1;tcnt=0;
dfs(now,now,0);
T2.build(T2.rt[now],1,sz2[now][now]);
for(int i=0;i<(int)e[now].size();i++){
int to=e[now][i].to;
if(vis[to])continue;
rt=0,sum=sz2[now][to];
getrt(to,now);
FA[rt]=now;dep2[rt]=dep2[now]+1;//dep2记录每个点在点分树上的深度
solve(rt);
}
}
//建点分树
//处理询问
inline int getans(int x){
int res=inf,temp=x;
while(temp){
res=min(res,getdis(temp,x)+T2.w[T2.rt[temp]]/*直接查询点分树上temp子树的最小值*/);
temp=FA[temp];
}
return res;
}
inline void Update(int x,int k){
int temp=x;
while(temp){
int DIS=getdis(x,temp);
if(k==1)T2.update1(T2.rt[temp],1,sz2[temp][temp],dfn2[temp][x],DIS);
else if(k==-1)T2.update1(T2.rt[temp],1,sz2[temp][temp],dfn2[temp][x],inf);
temp=FA[temp];
}
}
inline void calc(int x,int y,int w){
int p=x,q=y;
if(dep2[p]<dep2[q])swap(p,q);
while(dep2[p]>dep2[q])p=FA[p];
while(p!=q)p=FA[p],q=FA[q];
while(p){
if(dfn2[p][x]<dfn2[p][y])swap(x,y);
T2.update2(T2.rt[p],1,sz2[p][p],dfn2[p][x],dfn2[p][x]+sz2[p][x]-1,w);
p=FA[p];
}
}
int yes[N],tot;
//处理询问
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
n=read(),Q=read();
for(int i=1;i<n;i++){
int u=read(),v=read(),w=read();
e[u].push_back((zyx){v,w});
e[v].push_back((zyx){u,w});
edge.push_back((csq){u,v,w});
}
dfs1(1,0);dfs2(1,1);//树剖
for(int i=0;i<n-1;i++){
int u=edge[i].u,v=edge[i].v,w=edge[i].w;
if(dep[u]<dep[v])swap(u,v);
T1.update(1,1,n,dfn[u],w);
}//下放边权
rt=0,maxnson[rt]=inf,sum=n;
getrt(1,0);
solve(rt);
for(int i=1;i<=Q;i++){
int op=read();
if(op==1){
int q=read();
if(tot==0)cout<<"-1\n";
else cout<<getans(q)<<'\n';
}
else if(op==2){
int u=read();
if(yes[u]){
yes[u]=0;
tot--;
Update(u,-1);
}
else if(!yes[u]){
yes[u]=1;
tot++;
Update(u,1);
}
}
else if(op==3){
int a=read(),b=read(),w=read();
if(dep[a]<dep[b])swap(a,b);
calc(a,b,w-getdis(a,b));
T1.update(1,1,n,dfn[a],w);
}
}
return 0;
}