zoukankan      html  css  js  c++  java
  • Kruskal 重构树

    Kruskal 重构树

    建树步骤:

    • run Kruskal
    • 对于连接两个不在一个连通块的点 (u,v),新建节点 (k),在重构树上连边 ((u,k), (v,k)),点权为 ((u,v)) 的边权。并查集中 ((u,v)) 都和 (k) 连。

    性质:

    • 叶子节点为图中节点,非叶子节点为新建的边节点。

    • (lca(u,v)) 代表 (u-v) 路径的瓶颈的最值(取决 Kruskal 的时候边怎样排序)。

    • 是一个二叉堆结构(边权从根到叶是单调的)。

    ARC098D Donation(不正经的 Kruskal 重构树)

    考虑倒着来(捐钱 ( o) 收敛)。设 (c=max(a-b,0)),则约束条件变为到达一个点需要有 (c) 的钱,然后还能收敛 (b) 元钱。

    将所有边按照 (c) 从小到大排序。由于这道题是点权,所以我们就并不需要新建点来表示边,直接把 (c) 更大的作为 (c) 更小的重构树父亲即可。

    考虑 DP。(f_u) 表示从子树内某一点走到 (u) 所需的最少初始钱。显然叶节点的 (f_u=c_u)。对于答案,我们从某一点走到 (1) 然后即可遍历所有的节点,所以最终答案为 (f_1+sum b_u)。转移决策,我们考虑从哪个儿子走过来。

    [f_u=min_{vin son_u}{f_v,c_u-sum_{win T_v} b_w} ]

    https://www.luogu.com.cn/record/49245782

    NOI2018 归程

    考虑询问暴力怎么做。我们枚举切换节点 (u),满足 (v o u) 开车,(u o 1) 走路,这样的代价为 (dis_u),即 (1 o u) 的最短路。(v o u) 能开车,等价于 (v o u) 路径上的最小海拔要高于水位线。

    这种瓶颈问题可以考虑用 Kruskal 重构树。按海拔 (a) 从大到小排序后,建出的 Kruskal 重构树满足祖先边的海拔一定 (<) 后代边的海拔。所以,我们对于每一个询问的 (v),找到深度最小的节点 (u) 满足子树内的点的海拔全部都 (>p),然后 (u) 子树中的节点都是可以乘车到达的。所以 (ans=min_{iin T_u} d_{i})

    #include<bits/stdc++.h>
    #define int long long
    #define f(a) a.first
    #define s(a) a.second
    #define rep(i,a,b) for(register int i=(a);i<=(b);i++)
    #define per(i,a,b) for(register int i=(a);i>=(b);i--)
    using namespace std;
    const int N=400009,inf=0x3f3f3f3f3f3f3f3f;
    typedef pair<int,int> pii;
    
    inline long long read() {
        register long long x=0, f=1; register char c=getchar();
        while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
        while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-48,c=getchar();}
        return x*f;
    }
    
    int T,n,m,cnt,val[N],d[N],f[N][29],ans[N],lst;
    struct edge {int u,v,h;} ed[N];
    bool cmp(const edge &a,const edge &b) {return a.h>b.h;}
    vector<pii>e[N];
    vector<int>t[N];
    
    int id[N];
    int find(int i) {return i==id[i]?i:id[i]=find(id[i]);}
    void kruskal() {
    	sort(ed+1,ed+m+1,cmp);
    	rep(i,1,n) id[i]=i;
    	cnt=n;
    	rep(i,1,m) {
    		int u=ed[i].u,v=ed[i].v,h=ed[i].h;
    		if(find(u)!=find(v)) {
    			u=find(u), v=find(v);
    			val[++cnt]=h;
    			t[cnt].push_back(u), t[cnt].push_back(v);
    			id[u]=id[v]=id[cnt]=cnt;
    		}
    	}
    	rep(i,1,n) val[i]=inf;
    }
    
    bool vst[N];
    void dijkstra() {
    	memset(d,0x3f,sizeof(d)), d[1]=0;
    	priority_queue<pii>q; q.push(pii(0,1));
    	while(!q.empty()) {
    		int u=s(q.top()); q.pop();
    		if(vst[u]) continue; vst[u]=1;
    		for(auto ev:e[u]) {
    			int v=f(ev), w=s(ev);
    			if(d[u]+w<d[v]) d[v]=d[u]+w, q.push(pii(-d[v],v));
    		}
    	}
    }
    
    void dfs(int u) {
    	ans[u]=d[u];
    	rep(h,1,20) f[u][h]=f[f[u][h-1]][h-1];
    	for(auto v:t[u]) {
    		f[v][0]=u;
    		dfs(v);
    		ans[u]=min(ans[u],ans[v]);
    	}
    }
    int query(int u,int p) {
    	per(h,20,0) if(f[u][h]&&val[f[u][h]]>p) u=f[u][h];
    	return u;
    }
    
    signed main() {
    	T=read();
    	while(T--) {
    		memset(ed,0,sizeof(ed)), memset(e,0,sizeof(e)), memset(t,0,sizeof(t));
    		memset(f,0,sizeof(f)), lst=0, cnt=0, memset(vst,0,sizeof(vst));
    		n=read(), m=read();
    		rep(i,1,m) {
    			int u=read(), v=read(), l=read(), a=read();
    			ed[i]=(edge){u,v,a};
    			e[u].push_back(pii(v,l)), e[v].push_back(pii(u,l));
    		}
    		kruskal();
    		dijkstra();
    		dfs(cnt);
    		int Q=read(), K=read(), S=read();
    		while(Q--) {
    			int v=read(), p=read();
    			v=(v+K*lst-1)%n+1, p=(p+K*lst)%(S+1);
    			printf("%lld
    ",lst=ans[query(v,p)]);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    (转)获取/设置IFRAME内对象元素的几种JS方法
    XML校验之sun.tools.internal.xjc.Driver
    iframe自适应高度 (转)
    iframe根据内容自动增长 zz (转载)
    java.lang.NoSuchMethodError: org.apache.poi.hssf.usermodel.HSSFSheet.getMergedRegion
    jQuery取得select选中的值
    Mysql 语句大全
    Mysql 基础语句
    System.getProperty()方法大全
    一个对象什么时候才能被回收?
  • 原文地址:https://www.cnblogs.com/TetrisCandy/p/14642246.html
Copyright © 2011-2022 走看看