HDU6393(环套树)
题解: 很显然的是这个图必然是一个树上套一个简单环 我们考虑到只有树的情况 那么直接树链剖分+线段树就好了 如果多加一条边 qko告诉我可以类似基环树那样 取出这个环 那么我们可以对于一个询问分类 如果在一颗子树上我们可以直接查询即可 如果绕过环相连 那么可以取两点对应环上的点取min 加上两个点在不同子树中的路径长度即可
#include <bits/stdc++.h> #define ll long long #define link(x) for(edge *j=h[x];j;j=j->next) const int MAXN=1e5+10; const int inf=1e9; using namespace std; struct FastIO { static const int S=200; int wpos; char wbuf[S]; FastIO():wpos(0){} inline int xchar() { static char buf[S]; static int len=0,pos=0; if(pos==len) pos=0,len=fread(buf,1,S,stdin); if(pos==len) exit(0); return buf[pos++]; } inline int read() { int s=1,c=xchar(),x=0; while(c<=32) c=xchar(); if(c=='-') s=-1,c=xchar(); for(;'0'<=c&&c<='9';c=xchar()) x=x*10+c-'0'; return x*s; } ~FastIO() { if(wpos) fwrite(wbuf,1,wpos,stdout),wpos=0; } }io; int n,m; int F[MAXN],f[MAXN],b[MAXN]; int dep[MAXN],fa[MAXN],son[MAXN],num[MAXN],pos[MAXN],key[MAXN]; bool vis[MAXN],vi[MAXN]; int v1[MAXN]; struct edge{int t,id;ll v;bool f;edge*next,*rev;}e[MAXN<<2],*h[MAXN],*o=e; void add(int x,int y,ll v,int p){o->v=v;o->t=y;o->id=p;o->next=h[x];h[x]=o++;} int __v[MAXN]; int find1(int x){ if(x==F[x])return x; else return F[x]=find1(F[x]); } int _x,tot,c[MAXN],_t; void _dfs(int x){ __v[x]++; link(x)if(!j->f){ j->f=j->rev->f=true; if(__v[j->t]){_t=j->t;c[++tot]=x;vis[x]=1;return;} else _dfs(j->t); if(_t){c[++tot]=x;vis[x]=1;break;} } if(_t==x)_t=0; } void dfs(int v,int pre,int deep){ dep[v]=deep+1;fa[v]=pre;num[v]=1; link(v)if(j->t!=pre&&!vis[j->t]){ F[j->t]=v; key[j->t]=j->v; pos[j->id]=j->t; dfs(j->t,v,deep+1); num[v]+=num[j->t]; if(son[v]==-1||num[j->t]>num[son[v]])son[v]=j->t; } } int p[MAXN],fp[MAXN],tp[MAXN],cnt; void dfs1(int v,int td){ p[v]=++cnt;fp[p[v]]=v;tp[v]=td; if(son[v]!=-1)dfs1(son[v],td); link(v)if(j->t!=fa[v]&&j->t!=son[v]&&!vis[j->t])dfs1(j->t,j->t); } ll sum[MAXN<<2]; void built(int rt,int l,int r){ if(l==r){sum[rt]=key[fp[l]];return ;} int mid=(l+r)>>1; built(rt<<1,l,mid); built(rt<<1|1,mid+1,r); sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } ll ans; void querty(int rt,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr){ans+=sum[rt];return ;} int mid=(l+r)>>1; if(ql<=mid)querty(rt<<1,l,mid,ql,qr); if(qr>mid)querty(rt<<1|1,mid+1,r,ql,qr); } void update(int rt,int l,int r,int t,int vul){ if(l==r){sum[rt]=vul;return ;} int mid=(l+r)>>1; if(t<=mid)update(rt<<1,l,mid,t,vul); else update(rt<<1|1,mid+1,r,t,vul); sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } ll Sum(int u,int v){ int uu=tp[u];int vv=tp[v]; ll ans1=0; while(uu!=vv){ if(dep[uu]<dep[vv]){swap(uu,vv);swap(u,v);} ans=0;querty(1,1,n,p[uu],p[u]);ans1+=ans; u=fa[uu];uu=tp[u]; } if(dep[u]>dep[v])swap(u,v); //cout<<son[u]<<" "<<u<<" "<<v<<" "<<p[son[u]]<<" "<<p[v]<<" "<<ans1<<endl; if(u!=v)ans=0,querty(1,1,n,p[son[u]],p[v]),ans1+=ans; return ans1; } ll sum1[MAXN<<2]; int get_id(int x){return x&(-x);} void update1(int x,int vul){ //cout<<x<<" "<<vul<<endl; for(int i=x;i<=2*n;i+=get_id(i))sum1[i]+=vul; } ll querty1(int x){ ll ans1=0; for(int i=x;i>0;i-=get_id(i))ans1+=sum1[i]; return ans1; } int main(){ //freopen("k.out","w",stdout); int _=io.read();//scanf("%d",&_); while(_--){ n=io.read();m=io.read();memset(e,0,sizeof(e));memset(h,0,sizeof(h));o=e; memset(vis,0,sizeof(vis));memset(sum1,0,sizeof(sum1));memset(sum,0,sizeof(sum)); memset(vi,0,sizeof(vi)); memset(__v,0,sizeof(__v)); for(int i=1;i<=n;i++)F[i]=i,son[i]=-1,pos[i]=n+1; int u,v,vul;tot=0;cnt=0; for(int i=1;i<=n;i++)u=io.read(),v=io.read(),vul=io.read(),add(u,v,vul,i),add(v,u,vul,i),h[u]->rev=h[v],h[v]->rev=h[u]; for(int i=1;i<=n;i++)if(!__v[i])_dfs(i); for(int i=1;i<=tot;i++)v1[c[i]]=i; for(int i=1;i<=tot;i++)c[i+tot]=c[i],v1[c[i+tot]]=v1[c[i]]; tot*=2; for(int k=1;k<=tot-1;k++) link(c[k])if(j->t==c[k+1])b[k+1]=j->v,pos[j->id]=min(pos[j->id],k+1),vi[j->id]=1; for(int k=1;k<=tot;k++)update1(k,b[k]); tot/=2; for(int i=1;i<=tot;i++){dfs(c[i],0,0);dfs1(c[i],c[i]);} //for(int i=1;i<=n;i++)cout<<key[i]<<" "; // cout<<endl; built(1,1,n); int op,x,y; for(int i=1;i<=m;i++){ op=io.read();x=io.read();y=io.read(); if(op==0){ if(vi[x]){ x=pos[x]; update1(x,-1*b[x]);update1(x,y); update1(x+tot,-1*b[x]);update1(x+tot,y); b[x]=y; } else update(1,1,n,p[pos[x]],y); } else{ int t1=find1(x);int t2=find1(y); if(t1==t2)printf("%lld\n",Sum(x,y)); else{ ll ans1=Sum(x,t1);ans1+=Sum(y,t2); t1=v1[t1];t2=v1[t2]; if(t1>t2)swap(t1,t2); ans1+=min(querty1(t2)-querty1(t1),querty1(t1+tot)-querty1(t2)); printf("%lld\n",ans1); } } } } return 0; }