【HDU 6393】暑期多校day7 Traffic Network in Numazu (基环树、树链剖分)

题目大意

给出一棵基环树,有两种操作:1)修改一条边的边权,2)查询一个点到另一个点的最小距离。

解题思路

基环树其实可以形象的理解为一个长了好几棵树的环,那么,取两个点共有以下两种情况:

  1. 两点在同一棵树上;
  2. 两点在不同根的两棵树上;

对于在同一棵树上的两个点,问题就是简单的树链剖分;对于在不同树上的两个点,距离可以转化为“两结点到根节点的距离+环上两个根节点的距离”。

树上点的距离用树链剖分维护,环上的距离用一个树状数组维护。

代码

#include <bits/stdc++.h>
using namespace std;

const int BUF=80000000;
char Buf[BUF], *buf=Buf;
inline void read(int& a) {for(a=0;*buf<48;buf++); while(*buf>47) a=a*10+*buf++-48;}

const int maxn=int(1e5)+111;
typedef long long ll;
int n,m;

struct Edge {
    int from,to,next,cost;
    Edge() {}
    Edge(int f,int a,int b,int c):from(f),to(a),next(b),cost(c) {}
}eage[maxn*2];
int head[maxn], tot=0;

void init_eage() {
    tot=0;
    for(int i=1;i<=n;++i) head[i]=-1;
    return;
}

*void add_eage(int u,int v,int w) {
    eage[tot]=Edge(u,v,head[u],w), head[u]=tot++;
    eage[tot]=Edge(v,u,head[v],w), head[v]=tot++;
*    return;
}.

int sta[maxn], tp=0;
int cir[maxn], cnt=0;
bool insta[maxn], incir[maxn];

void init_dfs() {
    tp=cnt=0;
    for(int i=1;i<=n;++i)
        insta[i]=incir[i]=false;
	return;
}

bool get_circle(int u,int fa) {
    if(insta[u]) {
        for(int i=tp;;--i) {
            cir[++cnt]=sta[i], incir[sta[i]]=true;
            if(sta[i]==u) break;
        }
        return true;
    }
    insta[u]=true, sta[++tp]=u;
    for(int i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa) {
        bool flag=get_circle(eage[i].to,u);
        if(flag) return true;
    }
    insta[u]=false, tp--;
    return false;
}

int val[maxn];

void get_val(int u,int fa) {
    for(int i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa && !incir[eage[i].to]) {
        val[eage[i].to]=eage[i].cost;
        get_val(eage[i].to,u);
    }
    return;
}

int fa[maxn], dep[maxn], siz[maxn], son[maxn];
void dfs1(int u,int f,int d) {
    fa[u]=f, siz[u]=1, dep[u]=d, son[u]=0;
    for(int i=head[u];~i;i=eage[i].next) if(eage[i].to!=f && !incir[eage[i].to]) {
        int v=eage[i].to;
        dfs1(v,u,d+1);
        siz[u]+=siz[v];
        if(!son[u] || siz[v]>siz[son[u]]) 
            son[u]=v;
    }
    return;
}

int bel[maxn], top[maxn], ind[maxn];
vector<int> seq[maxn];

void dfs2(int u,int rt) {
    seq[rt].push_back(u);
    ind[u]=(int)seq[rt].size()-1;
    bel[u]=rt;
    if(u==son[fa[u]]) top[u]=top[fa[u]];
    else top[u]=u;
    if(son[u]) dfs2(son[u],rt);
    for(int v,i=head[u];~i;i=eage[i].next) if((v=eage[i].to)!=son[u] && v!=fa[u] && !incir[v])
        dfs2(v,rt);
    return;
}

void init_val() {
    for(int i=1;i<=n;++i)
        val[i]=0, seq[i].clear();
    return;
}

#define mid ((l+r)>>1)
const int maxtot=maxn*20;
int root[maxn], ls[maxtot], rs[maxtot], pt;
ll sum[maxtot];

void node_init(int k) {
    ls[k]=rs[k]=sum[k]=0;
    return;
}

void build_(int k,int l,int r,int rt) {
    if(l==r) {
        sum[k]=val[seq[rt][l]];
        return;
    }
    if(!ls[k]) ls[k]=++pt, node_init(pt);
    if(!rs[k]) rs[k]=++pt, node_init(pt);
    build_(ls[k],l,mid,rt), build_(rs[k],mid+1,r,rt);
    sum[k]=sum[ls[k]]+sum[rs[k]];
    return;
}
void tree_build() {
    register int i;
    pt=0;
    for(i=1;i<=cnt;++i) {
        get_val(cir[i],0);
        dfs1(cir[i],0,1), dfs2(cir[i],cir[i]);
        root[cir[i]]=++pt, node_init(pt);
        build_(root[cir[i]],0,seq[cir[i]].size()-1,cir[i]);
    }
    return;
}

int POS;
ll VAL;
void modify(int k,int l,int r) {
    if(l==r) {
        sum[k]=VAL;
        return;
    }
    if(POS<=mid) modify(ls[k],l,mid);
    if(POS> mid) modify(rs[k],mid+1,r);
    sum[k]=sum[ls[k]]+sum[rs[k]];
    return;
}
void tree_modify(int pos,int val) {
    POS=ind[pos], VAL=val;
	modify(root[bel[pos]],0,seq[bel[pos]].size()-1);
    return;
}

int L,R;
ll query_(int k,int l,int r) {
    if(L<=l && r<=R) return sum[k];
    ll res=0;
    if(L<=mid) res+=query_(ls[k],l,mid);
    if(R> mid) res+=query_(rs[k],mid+1,r);
    return res;
}
ll query(int u,int v,int rt) {
    L=ind[u], R=ind[v];
    if(L>R) swap(L,R);
    return query_(root[rt],0,(int)seq[rt].size()-1);
}

ll tree_query(int u,int v,int rt) {
    if(u==v) return 0;
    ll res=0;
    while(top[u]!=top[v]) {
	    if(dep[top[u]]<dep[top[v]]) swap(u,v);
        res+=query(u,top[u],rt);
        u=fa[top[u]];
    }
    if(dep[u]>dep[v]) swap(u,v);
    res-=query(u,u,rt);
	res+=query(u,v,rt);
    return res;
}

#define lowbit(k) ((k)&(-(k)))
	ll vc[maxn], cir_sum=0;
	int pos[maxn];
	
	void cir_add(int pos,ll val) {
    for(;pos<=n;pos+=lowbit(pos))
        vc[pos]+=val;
    return;
}
ll vc_query(int pos) {
    	ll res=0;
    for(;pos>=1;pos-=lowbit(pos))
        res+=vc[pos];
    return res;
}	
void get_cir_val(int u,int last,int p) {
	if(p==cnt) return;
	for(int i=head[u];~i;i=eage[i].next) if(eage[i].to==cir[p+1]) {
	    cir_add(p+1,eage[i].cost);
	    get_cir_val(eage[i].to,u,p+1);
	}
	 return;
 }
	
void init_cir() {
	register int i;
	cir_sum=0;
	for(i=0;i<=n;++i)
	    pos[i]=vc[i]=0;
  	return;
}
	
void cir_build() {
 	register int i;
	for(i=1;i<=cnt;++i)
	     pos[cir[i]]=i;
	get_cir_val(cir[1],0,1);
	for(i=0;i<tot;++i) if(incir[eage[i].from] && incir[eage[i].to])
	    cir_sum+=eage[i].cost;
	 cir_sum>>=1;
	 return;
}

ll cir_query(int u,int v) {
    if(pos[u]>pos[v]) swap(u,v);
    ll res1=vc_query(pos[v])-vc_query(pos[u]);
    return min(res1,cir_sum-res1);
}

ll QUERY(int u,int v) {
    if(bel[u]==bel[v])
        return tree_query(u,v,bel[u]);
    ll res=tree_query(u,bel[u],bel[u])+tree_query(v,bel[v],bel[v]);
    res+=cir_query(bel[u],bel[v]);
    return res;
}

void MODIFY(int id,ll val) {
    id=(id-1)<<1;
    int u=eage[id].from, v=eage[id].to;
    if(incir[u] && incir[v]) {
        if(pos[u]>pos[v]) swap(u,v);
        cir_sum-=eage[id].cost;
        if(pos[u]!=1 || pos[v]!=cnt) cir_add(pos[v],-eage[id].cost);
        eage[id].cost=eage[id^1].cost=val;
        cir_sum+=eage[id].cost;
        if(pos[u]!=1 || pos[v]!=cnt) cir_add(pos[v],eage[id].cost);
    }
    else {
        if(dep[u]>dep[v]) swap(u,v);
        eage[id].cost=eage[id^1].cost=val;
        tree_modify(v,val);
    }
    return;
}

void init() {
    init_cir();
    init_val();
    init_dfs();
    init_eage();
    return;
}

void work() {
    read(n), read(m);
    init();
    register int i,u,v,w;
    for(i=0;i<n;++i) {
        read(u), read(v), read(w);
        add_eage(u,v,w);
    }

    get_circle(1,0);
    tree_build();
    cir_build();

    int op,x,y;
    for(i=1;i<=m;++i) {
        read(op), read(x), read(y);
        if(op==0) MODIFY(x,y);
        else printf("%I64d\n",QUERY(x,y));
    }
    return;
}

int main() {
	#ifndef ONLINE_JUDGE
	#endif
    fread(Buf,1,BUF,stdin);
    int T;
    for(read(T);T;T--)
        work();

    return 0;
}

若您觉得此篇博客写得不错,请别忘了点赞并关注我哦 >_<

猜你喜欢

转载自blog.csdn.net/cza0927/article/details/82829534