• 【bzoj 4046 加强版】Pork barrel


    刚考完以为是神仙题……后来发现好像挺蠢的…… QwQ

    题意

      给你一张 (n) 个点 (m) 条边的无向图(不一定连通),有 (q) 组询问,每组询问给你 (2) 个正整数 (l,h),你需要选出一些边,满足边权都在 ([l,h]) 范围内,连通尽量多的点对,在此基础上使得边权和最小。
      (1le n,m,qle 10^5,space 1le w_i,l,hle 10^4)(原题 (nle 1000,space qle 10^6)

    题解

      动态最小生成树(汗)
      我怎么什么都没写过
      考场上花 10 分钟写了 5 分 (O(qn)) 暴力就滚了

      假设这题可以离线,先将所有边按权值从大到小排序。
      依次判断每条边的两端点是否连通,若未连通则连上(这样连通的点对数必定增多),若连通则替换掉一条树上这两点之间的简单路径上 权值最大的一条边(( ext{cut}) 一下权值最大的那条边,( ext{link}) 一下这条边)。
      加边的同时动态处理询问。对于一组询问 ([L,R]),若当前插入的边的权值是 (ge L) 的最小值,则我们决定处理这组询问。此时最小生成(森林)上的所有边权都 (ge L),我们直接扔掉所有权值 (gt R) 的边,剩余的边的权值和就是答案。发现边权很小,所以可以用树状数组动态维护最小生成(森林)中的边权,第 (i) 位记录所有权值为 (i) 的边的权值和,单点修改,区间查询。

      考虑在线,我想这题时居然忘了加边和询问是分开的了……
      依然把边按权值从大到小排序,每加入一条边时,第 (i) 个版本继承第 (i+1) 个版本,在主席树的第 (w_i) 个版本上单点修改即可。在线处理询问 ([L,R]) 时在主席树的第 (L) 个版本上区间查询即可。
      复杂度 (O(nlog n))
      仔细想想好像确实挺水的,所以还是我太菜了

      附注:
      1. (LCT) 一般维护点权,边权不太好维护,可以把第 (i) 条边转成一个编号为 (i+n) 的点,然后加入这条边的时候 把这个点与边的两端点 ( ext{link}) 一下即可
      2. 注意主席树的空间是 (O(2mlog w)) 的!!!不是 (O(10000log 10000))!!!因为这个 sb 问题调了一小时 zbl

    #include<bits/stdc++.h>
    #define N 200010
    using namespace std;
    inline int read(){
    	int x=0; bool f=1; char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    	for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
    	if(f) return x; return 0-x;
    }
    int n,m,online,q;
    struct inp{int u,v,w;}a[N<<1];
    inline bool cmp(inp a, inp b){
    	return a.w>b.w;
    }
    namespace LCT{
    	#define son(x,fx) tr[x].son[fx]
    	struct Tree{int fa,son[2],v,mx_id; bool r;}tr[N<<1];
    	inline bool isRoot(int x){
    		return son(tr[x].fa,0)!=x && son(tr[x].fa,1)!=x;
    	}
    	inline bool idf(int x){
    		return son(tr[x].fa,1)==x;
    	}
    	void pushup(int x){
    		tr[x].mx_id=x;
    		if(tr[tr[son(x,0)].mx_id].v > tr[tr[x].mx_id].v) tr[x].mx_id=tr[son(x,0)].mx_id;
    		if(tr[tr[son(x,1)].mx_id].v > tr[tr[x].mx_id].v) tr[x].mx_id=tr[son(x,1)].mx_id;
    	}
    	void pushdown(int x){
    		if(tr[x].r){
    			swap(son(x,0),son(x,1));
    			tr[son(x,0)].r^=1, tr[son(x,1)].r^=1;
    			tr[x].r=0;
    		}
    	}
    	void pd(int x){
    		if(!isRoot(x)) pd(tr[x].fa);
    		pushdown(x);
    	}
    	inline void connect(int x, int f, int fx){
    		tr[x].fa=f, son(f,fx)=x;
    	}
    	void rotate(int x){
    		int y=tr[x].fa, z=tr[y].fa, idf_x=idf(x), idf_y=idf(y), B=son(x,idf_x^1);
    		if(!isRoot(y)) connect(x,z,idf_y);
    		else tr[x].fa=z;
    		connect(B,y,idf_x), connect(y,x,idf_x^1);
    		pushup(y), pushup(x);
    	}
    	void splay(int x){
    		pd(x);
    		int f;
    		for(; !isRoot(x); ){
    			f=tr[x].fa;
    			if(!isRoot(f)) rotate(idf(x)==idf(f) ? f : x);
    			rotate(x);
    		}
    	}
    	void access(int x){
    		for(int y=0; x; x=tr[y=x].fa){
    			splay(x);
    			son(x,1)=y;
    			pushup(x);
    		}
    	}
    	void makeroot(int x){
    		access(x), splay(x), tr[x].r^=1;
    	}
    	void link(int x, int y){
    		makeroot(x);
    		tr[x].fa=y;
    	}
    	int cutMax(int x, int y){
    		makeroot(x);
    		access(y);
    		splay(y);
    		x=tr[y].mx_id;
    		splay(x);
    		tr[son(x,0)].fa=tr[son(x,1)].fa=0;
    		son(x,0)=son(x,1)=0;
    		return x;
    	}
    	#undef son
    }using namespace LCT;
    namespace PT{
    	#define son(x,fx) tr[o].son[fx]
    	int cnt,rt[100010];
    	struct Tree{int son[2],sum;}tr[200010*20];
    	void ins(int &o, int pre, int l, int r, int x, int v){
    		tr[o=++cnt] = tr[pre], tr[o].sum += v;
    		if(l==r) return;
    		int mid=l+r>>1;
    		if(x<=mid) ins(son(o,0),son(pre,0),l,mid,x,v);
    		else ins(son(o,1),son(pre,1),mid+1,r,x,v);
    	}
    	int query(int o, int l, int r, int L, int R){
    		if(!o) return 0;
    		if(L<=l && r<=R) return tr[o].sum;
    		int mid=l+r>>1, ret=0;
    		if(L<=mid) ret+=query(son(o,0),l,mid,L,R);
    		if(R>mid) ret+=query(son(o,1),mid+1,r,L,R);
    		return ret;
    	}
    }using namespace PT;
    namespace DSU{
    	int fa[N];
    	void init(){
    		for(int i=1; i<=n; ++i) fa[i]=i;
    	}
    	int find(int x){
    		if(fa[x]==x) return x;
    		return fa[x]=find(fa[x]);
    	}
    }using namespace DSU;
    int main(){
    	n=read(), m=read(), online=read();
    	for(int i=1; i<=m; ++i) a[i].u=read(), a[i].v=read(), a[i].w=read();
    	sort(a+1,a+m+1,cmp);
    	init();
    	int fu,fv;
    	for(int i=1; i<=m; ++i){
    		rt[a[i].w]=rt[a[i-1].w];
    		fu=find(a[i].u), fv=find(a[i].v);
    		if(fu==fv){
    			q=cutMax(a[i].u,a[i].v);
    			ins(rt[a[i].w],rt[a[i].w],1,a[1].w,LCT::tr[q].v,-LCT::tr[q].v);
    		}
    		else{
    			DSU::fa[fv]=fu;
    			q=n+i;
    		}
    		LCT::tr[q].v=a[i].w;
    		LCT::tr[q].mx_id=q;
    		link(a[i].u,q), link(q,a[i].v);
    		ins(rt[a[i].w],rt[a[i].w],1,a[1].w,a[i].w,a[i].w);
    	}
    	for(int i=a[1].w-1; i>0; --i)
    		if(rt[i]==0) rt[i]=rt[i+1];
    	
    	q=read();
    	int l,r,lastans=0;
    	while(q--){
    		l=read()-online*lastans, r=read()-online*lastans;
    		printf("%d
    ",lastans=query(rt[l],1,a[1].w,1,r));
    	}
    	return 0;
    }
    /*
    5 7 1
    1 2 2
    2 3 4
    3 4 3
    4 5 1
    5 1 3
    2 5 4
    1 4 5
    5
    1 2
    4 7
    11 12
    11 13
    18 19
    */
    
  • 相关阅读:
    网易官方」极客战记(codecombat)攻略-沙漠-跟上时间-keeping-time
    jenkins 通过使用crumbissuer停止job
    获取crumbIssuer
    解决docker容器vim高度宽度显示不正常
    嵌入skype标签
    pip --user参数
    python requests模块和 urllib.request模块
    python字符识别
    bs4解析xml文件,制作xml文件
    jenkins api
  • 原文地址:https://www.cnblogs.com/scx2015noip-as-php/p/bzoj4046.html
Copyright © 2020-2023  润新知