自闭了,调不动了
  • 板块P4197 Peaks
  • 楼主Rad_Forever
  • 当前回复3
  • 已保存回复3
  • 发布时间2022/7/17 12:22
  • 上次更新2023/10/27 19:54:24
查看原帖
自闭了,调不动了
538677
Rad_Forever楼主2022/7/17 12:22

这题我没写线段树合并也没写 Kruskal 重构树,而是敲了一个 Splay。

大致思路就是对于每一个点维护一棵 Splay,将询问离线排序后从小到大加边,用启发式合并的方式合并两颗 Splay。

#include<bits/stdc++.h>

#define RI register int

using namespace std;

namespace IO{
    inline int read(){
    	RI X=0, W=0;register char ch=getchar();
    	while(!isdigit(ch)) W|=ch=='-', ch=getchar();
    	while(isdigit(ch)) X=(X<<1)+(X<<3)+(ch^48), ch=getchar();
    	return W?-X:X;
	}
	inline void write(int x){
		if(x<0) x=-x, putchar('-');
		if(x>9) write(x/10);
		putchar(x%10+'0');
	}
}using namespace IO;

const int MAXN = 1e6+5;

int n, m, q;
int fa[MAXN];
int val[MAXN], siz[MAXN];
int ch[MAXN][2];
int root[MAXN];
int cnt[MAXN], sz[MAXN];
int trash[MAXN], tot;
int newnode;
int ans[MAXN];
int cnt_, sq[MAXN];

struct edge{
	int u, v, w;
	bool friend operator < (const edge &x, const edge &y){return x.w<y.w;}
}e[MAXN];

struct query{
	int u, x, k, id;
	bool friend operator < (const query &x, const query &y){return x.x<y.x;}
}ask[MAXN];

inline bool get(int x){return x==ch[fa[x]][1];}

inline void pushup(int x){
	siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+cnt[x];
	return ;
}

inline void rotate(int x){
	int f=fa[x], gf=fa[f], which=get(x), W=ch[x][!which];
	if(gf) ch[gf][get(f)]=x;
	ch[x][!which]=f, ch[f][which]=W;
	if(W) fa[W]=f;
	fa[f]=x, fa[x]=gf;
	pushup(f), pushup(x);
	return ;
}

inline void splay(int p, int x, int goal=0){
	int f;
	while((f=fa[x])!=goal){
		if(fa[f]!=goal) rotate(get(x)==get(f)?f:x);
		rotate(x);
	}
	if(!goal) root[p]=x;
	return ;
}

int f[MAXN];

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

inline int MakeNewnode(int v){
	int p;
	if(tot) p=trash[tot--];
	else p=++newnode;
	ch[p][0]=ch[p][1]=0;
	fa[p]=0, val[p]=v;
	cnt[p]=siz[p]=1;
	return p;
}

inline void ins(int p, int v){
	int now=root[p], las;
	while(now){
		if(val[now]==v){
			cnt[now]++;siz[now]++;
			return pushup(now), splay(p,now);
		}
		las=now, now=ch[now][val[now]<v];
		if(!now){
			now=MakeNewnode(v);
			fa[now]=las;ch[las][val[las]<v]=now;
			return pushup(las), splay(p,now);
		}
	}
	if(!root[p])
		root[p]=MakeNewnode(v);
}

inline int getans(int v, int x, int k){
	k=siz[x]-k+1;
	while(x){
		if(siz[ch[x][0]]>=k) x=ch[x][0];
		else {
			k-=siz[ch[x][0]];
			if(cnt[x]>=k) return splay(v,x), val[x];
			k-=cnt[x];
			x=ch[x][1];
		}
	}
	return -2333;
}

inline void dfs(int x){
	sq[++cnt_]=val[x];trash[++tot]=x;
	if(ch[x][0]) dfs(ch[x][0]);
	if(ch[x][1]) dfs(ch[x][1]);
	return ;
}

inline void add(int x){
	int xx=e[x].u, yy=e[x].v;
	xx=find(xx), yy=find(yy);
	if(xx==yy) return ;
	if(sz[xx]>sz[yy]) swap(xx,yy);
	if(siz[root[xx]]!=sz[xx]) exit(233);
	cnt_=0;dfs(root[xx]);
	if(cnt_!=sz[xx]) exit(1);//这个地方 dfs 出来的 Splay 大小和并查集大小不符
	for(int i=1;i<=cnt_;++i) ins(yy,sq[i]);
	f[xx]=yy;sz[yy]+=sz[xx];
	return ;
}

int main(){
	n=read(), m=read(), q=read();
	for(int i=1;i<=n;++i) f[i]=i, sz[i]=1, ins(i,read());
	for(int i=1;i<=m;++i) e[i]=edge{read(),read(),read()};
	sort(e+1,e+1+m);
	for(int i=1;i<=q;++i) ask[i]=query{read(),read(),read(),i};
	sort(ask+1,ask+1+q);int now=1;
	for(int i=1;i<=q;++i){
		while(now<=m && e[now].w<=ask[i].x) add(now), now++;
		if(sz[find(ask[i].u)]<ask[i].k) ans[ask[i].id]=-1;
		else ans[ask[i].id]=getans(f[ask[i].u],root[f[ask[i].u]],ask[i].k);
	}
	for(int i=1;i<=q;++i) write(ans[i]), putchar(10);
	return 0;
}
2022/7/17 12:22
加载中...