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;
    }
    
  • 相关阅读:
    T-SQL:事务锁下的并发处理(十五)
    C# Quartz定时任务corn时间设置详解
    C# QuartZ使用实例写成服务
    SQL SERVER 一个SQL语句的执行顺序
    SQL SERVER 如何判断是不是年,月最后一天
    SQL SERVER 如何声明一个变量
    SQL SERVER GO命令循环使用实例
    T-SQL:批GO使用实例(十四)
    VS2017进程为idXXXX 无法启动解决方案
    UI5-文档-4.20-Aggregation Binding
  • 原文地址:https://www.cnblogs.com/owenyu/p/7295609.html
Copyright © 2011-2022 走看看