zoukankan      html  css  js  c++  java
  • bzoj3545-bzoj3551-Peaks

    题意

    给出一个图,边有边权,点有点权,每次询问一个点 (x) 只走边权小于等于 (d) 的边能到达的点中点权第 (k) 大。

    强制在线,(nle 10^5,m,qle 5 imes 10^5)

    分析

    如果可以离线的话,我们可以用一个并查集(路径压缩)维护连通性,在并查集的每个点上存一个权值线段树,每次merge的时候就把下面的线段树合并到上面。做kruskal最小生成树,从小到大每次加完一种权值的边后处理这里的询问。这样的复杂度为 (O(nlog nalpha(n)))

    然而现在是强制在线,引入一种新的数据结构——kruskal重构树(我也不知道为什么是这个名字)。它的思想非常简单。kruskal的时候我们是从小到大添加边,那么我们还是用类似并查集的方法,每次合并的时候新建一个点,把需要合并的两个点都挂在这个新点的下面,新点的权值为这条边的边权。这样我们会得到一棵树,它满足新点的结构组成一个大根堆。那么如果我们要查询从一个点出发,边权小于等于 (d) 的边能到达的点,其实就是从这个点不断往上跳,保证经过的每个新点 (p) 的权值都小于等于 (d) 。最后走到的这个新点的整个子树就是我们能够走到的点。

    由于这棵树的高度没有保证,我们把这棵树建出来,做一个可持久化线段树的合并,倍增跳到合法的 (p) ,查询子树即可。复杂度为 (O(nlog n)),非常优秀。

    其实这题我还有一个想法。我们每次不新建点,而是按秩合并并查集,在每个点上开一个map,记录一下每个权值对应的线段树根,每次暴力往上跳到合法位置,在map上lower_bound以下,直接查询即可。复杂度也为 (O(nlog n))

    代码

    这不是kruskal重构树,是我那个方法。

    #include<bits/stdc++.h>
    using namespace std;
    inline char nchar() {
    	static const int bufl=1<<20;
    	static char buf[bufl],*a,*b;
    	return a==b && (b=(a=buf)+fread(buf,1,bufl,stdin),a==b)?EOF:*a++;
    }
    inline int read() {
    	int x=0,f=1;
    	char c=nchar();
    	for (;!isdigit(c);c=nchar()) if (c=='-') f=-1;
    	for (;isdigit(c);c=nchar()) x=x*10+c-'0';
    	return x*f;
    }
    inline void write(int x) {
    	if (x==0) puts("0"); else if (x==-1) puts("-1"); else {
    		static char s[20];
    		int tot=0;
    		for (;x;x/=10) s[++tot]=x%10+'0';
    		while (tot) putchar(s[tot--]);
    		puts("");
    	}
    }
    const int maxn=1e5+1;
    const int maxm=5e5+1;
    const int inf=1e9+7;
    int h[maxn],c[maxn],ls=0,n,m,q;
    pair<int,pair<int,int> > e[maxm];
    namespace sgt {
    	const int maxp=5e6+1;
    	struct node {
    		int l,r,size;
    	} t[maxp];
    	int tot=0;
    	void inc(int &x,int l,int r,int p) {
    		if (!x) x=++tot;
    		++t[x].size;
    		if (l==r) return;
    		int mid=(l+r)>>1;
    		p<=mid?inc(t[x].l,l,mid,p):inc(t[x].r,mid+1,r,p);
    	}
    	inline void inc(int &x,int p) {inc(x,1,ls,p);}
    	int merge(int x,int y,int l,int r) {
    		if (!x) return y;
    		if (!y) return x;
    		int p=++tot,mid=(l+r)>>1;
    		if (l==r) {
    			t[p].size=t[x].size+t[y].size;
    			return p;
    		}
    		t[p].l=merge(t[x].l,t[y].l,l,mid);
    		t[p].r=merge(t[x].r,t[y].r,mid+1,r);
    		t[p].size=t[t[p].l].size+t[t[p].r].size;
    		return p;
    	}
    	int query(int x,int l,int r,int k) {
    		if (l==r) return l;
    		int mid=(l+r)>>1;
    		return k<=t[t[x].l].size?query(t[x].l,l,mid,k):query(t[x].r,mid+1,r,k-t[t[x].l].size);
    	}
    	inline int query(int x,int k) {
    		if (k==0 || k>t[x].size) return -1; 
    		return query(x,1,ls,t[x].size-k+1);
    	}
    }
    namespace st { 
    	int rk[maxn],f[maxn],w[maxn],last[maxn];
    	map<int,int> mp[maxn];
    	inline void init(int n) {for (int i=1;i<=n;++i) rk[i]=0,w[i]=-1,f[i]=i;}
    	int find(int x,int d=inf) {
    		for (;f[x]!=x && w[x]<=d;x=f[x]);
    		return x;
    	}
    	int uni(int x,int y,int v) {
    		if (rk[x]>rk[y]) swap(x,y);
    		f[x]=y,w[x]=v,rk[y]+=(rk[x]==rk[y]);
    		int tmp=mp[y].rbegin()->second;
    		int &rt=mp[y][v];
    		rt=sgt::merge(rt?rt:tmp,mp[x].rbegin()->second,1,ls);
    	}
    	int query(int x,int val,int k) {
    		int fx=find(x,val);
    		map<int,int>::iterator it=mp[fx].upper_bound(val);
    		int rt=(--it)->second;
    		return sgt::query(rt,k);
    	}
    }
    inline bool cmp(int x,int y) {return st::rk[x]<st::rk[y];}
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("test.in","r",stdin);
    #endif
    	n=read(),m=read(),q=read();
    	st::init(n);
    	for (int i=1;i<=n;++i) c[++ls]=h[i]=read();
    	sort(c+1,c+ls+1),ls=unique(c+1,c+ls+1)-c-1;
    	for (int i=1;i<=n;++i) h[i]=lower_bound(c+1,c+ls+1,h[i])-c;
    	for (int i=1;i<=m;++i) {
    		int x=read(),y=read(),w=read();
    		e[i]=make_pair(w,make_pair(x,y));
    	}
    	sort(e+1,e+m+1);
    	for (int i=1;i<=n;++i) {
    		sgt::inc(st::mp[i][-1],h[i]);
    	}
    	for (int i=1;i<=m;++i) {
    		int &w=e[i].first,&x=e[i].second.first,&y=e[i].second.second;
    		int fx=st::find(x),fy=st::find(y);
    		if (fx!=fy) st::uni(fx,fy,w);
    	}
    	int ans=0;
    	while (q--) {
    		int x=read()^ans,val=read()^ans,k=read()^ans;
    		ans=st::query(x,val,k);
    		if (ans!=-1) ans=c[ans];
    		write(ans);
    		if (ans==-1) ans=0;
    	}
    	return 0;
    }
    
  • 相关阅读:
    智慧养老民政监管平台建设方案
    CF600E Lomsat gelral dsu on tree
    dsu on tree详解
    【Spring 从0开始】Spring5 新功能,整合日志框架 Log4j2
    【Spring 从0开始】JdbcTemplate 数据库事务管理
    【Spring 从0开始】JdbcTemplate 数据库事务参数
    【Spring 从0开始】JdbcTemplate 数据库事务管理
    【Spring 从0开始】JdbcTemplate 操作数据库
    【Spring 从0开始】AOP 操作
    【Spring 从0开始】AOP 操作中的相关术语、环境准备
  • 原文地址:https://www.cnblogs.com/owenyu/p/7295609.html
Copyright © 2011-2022 走看看