Peaks

很好我心态崩了。
————————————————
这里给出两种做法,代码上都有一些问题,建议不要\(copy\).
一:离线做法
考虑直接线段树合并,把问题按边权排。
做完了。

离线做法
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
#define M 2000003
#define N 100003

ll head[N];
ll n,m;

ll v[M],ls[M],rs[M],fa[N],cnt,t[M];

inline void up(ll now){v[now] = v[ls[now]] + v[rs[now]];}

inline ll get(ll now){return now == fa[now] ? now : fa[now] = get(fa[now]);}

#define mid ((l + r) >> 1)

ll tag;

inline int build(int l,int r,int to){
	int now = ++cnt;
//	std::cout<<now<<" "<<l<<" "<<r<<std::endl;
	if(l == r){
		t[now] = tag;
		v[now] = 1;
		return now;
	}
	if(to <= mid)
	ls[now] = build(l,mid,to);
	else
	rs[now] = build(mid + 1,r,to);
	up(now);
	return now;
}

inline int merge(ll a,ll b,ll l,ll r){
//	std::cout<<a<<" "<<b<<" "<<l<<" "<<r<<std::endl;
	if(!a || !b)
	return a + b;
	if(l == r){
		v[a] += v[b];
		return a;
	}
	ls[a] = merge(ls[a],ls[b],l,mid);
	rs[a] = merge(rs[a],rs[b],mid + 1,r);
	up(a);
	return a;
}

inline int Q(ll now,ll q,ll l,ll r){
//	std::cout<<now<<" "<<q<<" "<<l<<" "<<r<<" "<<v[now]<<" "<<std::endl;
	if(l == 1 && r == n && q > v[now])
	return -1;
	if(l == r)
	return t[now];
	if(v[rs[now]] >= q)
	return Q(rs[now],q,mid + 1,r);
	else
	return Q(ls[now],q - v[rs[now]],l,mid);
}

inline void dfs(ll now,ll l,ll r){
	if(now){
//		std::cout<<now<<" "<<l<<" "<<r<<" "<<v[now]<<std::endl;
		dfs(ls[now],l,mid);
		dfs(rs[now],mid + 1,r);
	}
}

struct P{int to,s,v;}e[N << 4];

inline bool operator < (P a,P b){return a.v < b.v;}

struct Qp{int v,x,k,id;}Qi[N * 5];

ll ans[N * 5];

inline bool operator < (Qp a,Qp b){return a.x < b.x;}

ll q,num[N],b[N],s;

int main(){
	scanf("%lld%lld",&n,&m);
	scanf("%lld",&q);	
	for(int i = 1;i <= n;++i)
	fa[i] = i;
	for(int i = 1;i <= n;++i)
	scanf("%lld",&num[i]),b[++b[0]] = num[i];
	std::sort(b + 1,b + n + 1);
	s = std::unique(b + 1,b + n + 1) - b - 1;
	for(int i = 1;i <= n;++i){
		ll x = std::lower_bound(b + 1,b + s + 1,num[i]) - b;
		tag = i;
		head[i] = build(1,n,x);
	}
	for(int i = 1;i <= m;++i)
		scanf("%d%d%d",&e[i].s,&e[i].to,&e[i].v);
	std::sort(e + 1,e + m + 1);		
//	for(int i = 1;i <= m;++i)
//		std::cout<<e[i].s<<" "<<e[i].to<<" "<<e[i].v<<std::endl;		
	for(int i = 1;i <= q;++i){
		Qi[i].id = i;
		scanf("%d%d%d",&Qi[i].v,&Qi[i].x,&Qi[i].k);
	}
	std::sort(Qi + 1,Qi + q + 1);
//	for(int i = 1;i <= q;++i)
//	std::cout<<Qi[i].v<<" "<<Qi[i].x<<" "<<Qi[i].k<<std::endl;
	ll now = 1;
	for(int i = 1;i <= q;++i){
//		std::cout<<Qi[i].v<<" "<<Qi[i].x<<" "<<Qi[i].k<<std::endl<<std::endl;
		while(e[now].v <= Qi[i].x && now <= m){
//			std::cout<<e[now].s<<" "<<e[now].to<<" "<<e[now].v<<std::endl;
//			std::cout<<now<<std::endl;
			ll x = e[now].s,y = e[now].to;
			ll fx = get(x),fy = get(y);
			if(fx != fy){
//			std::cout<<fx<<" "<<fy<<" "<<head[fx]<<" "<<head[fy]<<std::endl;			
			fa[fx] = fy;
			head[fy] = merge(head[fx],head[fy],1,n);
			}	
			++now;
		}
//		puts("");
		ll fx = get(Qi[i].v);
//		std::cout<<Q(head[fx],Qi[i].k,1,n)<<std::endl;
		ll an = Q(head[fx],Qi[i].k,1,n);
		if(an != -1)
		ans[Qi[i].id] = num[an];
		else
		ans[Qi[i].id] = -1;	
	}  
	for(int i = 1;i <= q;++i)
	std::cout<<ans[i]<<std::endl;
}

二:在线做法
考虑重构树,那么在一个权值为\(k\)的方点下的原点均可以小于等于\(k\)的边走到。
倍增+主席树做完了。
(莫名\(RE\)心态没了)

在线做法
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll int
#define N 200005

ll n,m,q,num[N],b[N];

struct Map{int to,s,v;}e[N];

inline bool operator < (Map a,Map b){return a.v < b.v;}

//________________________//map

ll head[N << 1],v[N << 2],cnt;

struct T{int to,next;}t[N * 6];

inline void add(int x,int y){
//	std::cout<<x<<" "<<y<<std::endl;
	t[++cnt].to = y;
	t[cnt].next = head[x];
	head[x] = cnt;
}

ll l[N << 1],r[N << 1],tnum[N],dfncnt,fi[N << 1][25];

inline void dfs(int u,int f){
	if(u == 0 || u == f)
	return ;
//	std::cout<<u<<" "<<v[u]<<std::endl;
	fi[u][0] = f;
	for(int i = 1;i <= 19;++i)
	fi[u][i] = fi[fi[u][i - 1]][i - 1];
	l[u] = dfncnt;
	if(head[u] == 0){
		tnum[++dfncnt] = std::lower_bound(b + 1,b + b[0] + 1,num[u]) - b;
		r[u] = dfncnt;
		return ;
	}
	for(int i = head[u];i;i = t[i].next){
		int v = t[i].to;
		if(v == f)
		continue;
		dfs(v,u);
	}
	r[u] = dfncnt;
}

//________________________//tree

ll fa[N];

inline ll find(int x){return (x == fa[x]) ? x : fa[x] = find(fa[x]);}

//________________________//dsu

int tcnt;

int thead[N];

#define mid ((l + r) >> 1)

struct Seg{int l,r,s;Seg(){l = r = s = 0;};}Tr[N * 40];

#define l(x) Tr[x].l
#define r(x) Tr[x].r
#define v(x) Tr[x].s

//tnum[M]


inline void change(int &now,int pre,int l,int r,int to){
	if(!now)now = ++ tcnt ;
//	std::cout<<now<<" "<<pre<<" "<<l<<" "<<r<<" "<<to<<std::endl;	
	v(now) = v(pre) + 1;
	if(l == r)return;
	if(to > mid){l(now) = l(pre),change(r(now),r(pre),mid + 1,r,to);}
	else{r(now) = r(pre),change(l(now),l(pre),l,mid,to);}
}

inline void build(){
	for(int i = 1;i <= n;++i)
	change(thead[i],thead[i - 1],1,n,tnum[i]);
}
inline ll grt(int u,ll x){
	for(int i = 19;i >= 0;--i){
		if(v[fi[u][i]] <= x)
		u = fi[u][i];
	}
	return u;
}

inline ll Q(int lnow,int rnow,int l,int r,int k){
	int rk = v(r(rnow)) - v(r(lnow));
//	std::cout<<lnow<<" "<<rnow<<" "<<l<<" "<<r<<" "<<k<<std::endl;
	if(l == r){
		if(k - (v(rnow) - v(lnow)) == 0)
		return l;
		else
		return 0;
	}
	if(rk >= k)
	return Q(r(lnow),r(rnow),mid + 1,r,k);
	else
	return Q(l(lnow),l(rnow),l,mid,k - rk);
}

//______________________//Seg tree

ll tot;

inline void kruskal(){
	ll bcnt = 0;
	tot = n;
	for(int i = 1;i <= m && bcnt < n - 1;++i){
		ll x = e[i].s,y = e[i].to;
		ll fx = find(x),fy = find(y);
		if(fx != fy){
//			std::cout<<e[i].s<<" "<<e[i].to<<" "<<e[i].v<<" "<<fx<<" "<<fy<<std::endl;
			v[++tot] = e[i].v;
			add(tot,fx);
			add(tot,fy);
			fa[tot] = fa[fx] = fa[fy] = tot;
			bcnt ++ ;
		}
	}
}

//_______________________//rebuild;

int main(){
//	freopen("q.in","r",stdin);
//	freopen("q.ans","w",stdout);	
	scanf("%d%d%d",&n,&m,&q);
	for(int i = 1;i <= n;++i)
	scanf("%d",&num[i]),b[++b[0]] = num[i];
	std::sort(b + 1,b + b[0] + 1);
	b[0] = std::unique(b + 1,b + b[0] + 1) - b - 1;
	for(int i = 1;i <= m;++i){scanf("%d%d%d",&e[i].s,&e[i].to,&e[i].v);}
	std::sort(e + 1,e + m + 1);
	for(int i = 1;i <= n;++i)
	fa[i] = i;
//	puts("");
	kruskal();
	dfs(find(1),0);
	build();
	b[0] = -1;
	v[0] = 1e9 + 7;
	for(int i = 1;i <= q;++i){
		ll v,x,k;
		scanf("%d%d%d",&v,&x,&k);
		ll rt = grt(v,x);
//		std::cout<<rt<<std::endl;
		std::cout<<b[Q(thead[l[rt]],thead[r[rt]],1,n,k)]<<std::endl;
	}
}

/*
7 7 70
11493 8611 10935 23931 3939 16004 14404 
3 7 727057
3 2 860811
3 1 739841
3 5 123028
6 1 501761
2 6 119601
3 4 760129
4 372996 1
*/

建议重构树的题目能离线做还是离线做吧,很难调。

posted @ 2021-05-20 21:47  fhq_treap  阅读(202)  评论(0编辑  收藏  举报