[BZOJ 3551+3545]Peaks

加强:题目传送-BZOJ3551

原味:题目传送-BZOJ3545

题意:

有一个\(n\)个点\(m\)条边的无向图,点有点权,边有边权。
\(q\)次询问(u,val,k)
表示从\(u\)出发,经过的边权都小于等于\(val\),能到达的所有点中,点权第\(k\)大的权值
强制在线
$n \le 100000,m \le 500000,q \le 300000 $

题解:

做过NOI2018D1T1的再做这题就思路清晰了
你需要先学会Kruskal重构树,也不是什么高大上的东西..
然后这就变成了一棵树,按DFS序将叶子节点映射到一个序列上
转换为区间第K大,就随便做了..我用的是主席树

过程:

先忘了强制在线,再各种细节..

代码:

const int N=100010,M=500010,lgN=18,ALL=N<<1;
int n,m,q,rt,all;
int h[N];
int head[ALL],nxt[ALL],to[ALL],lst=0;
int bd[ALL],fa[ALL];
inline void adde(int x,int y) {
	assert(fa[y]==x);
	nxt[++lst]=head[x]; to[lst]=y; head[x]=lst;
}
namespace KRU {
	struct EDGE {
		int x,y,c;
		inline void in() {
			read(x); read(y); read(c);
		}
		bool operator < (const EDGE &a)const {
			return c<a.c;
		}
	}e[M];
	int fat[N],ref[N],ind=0;
	int father(int x) {return x==fat[x] ? x : fat[x]=father(fat[x]);}
	inline int Kruskal() {
		sort(e+1,e+m+1); int k=0; ind=n;
		for(int i=1;i<=n;i++) fat[i]=ref[i]=i;
		for(int i=1;i<=m;i++) {
			int fx=father(e[i].x),fy=father(e[i].y);
			if(fx!=fy) {
				int np=++ind; fa[ref[fy]]=fa[ref[fx]]=np;
				adde(np,ref[fy]); adde(np,ref[fx]); bd[np]=e[i].c;
				ref[fy]=np; ref[fx]=0; fat[fx]=fy;
				if(++k==n-1) return ind;
			}
		}
		int np=++ind; bd[np]=INF;
		for(int i=1;i<=n;i++)
			if(father(i)==i) {
				fa[ref[i]]=np;
				adde(np,ref[i]);
			}
		// printf("lst=%d\n",lst);
		return ind;
	}
}
int le[ALL],t_s[ALL],s_t[ALL],ind=0;
namespace TREE {
	int anc[ALL][lgN+2],lim[ALL][lgN+2],dep[ALL],sz[ALL];
	void Print(int u) {
		for(int i=1;i<dep[u];i++) putchar('\t'); printf("%d:%d %d\n",u,fa[u],bd[u]);
		for(int i=head[u];i;i=nxt[i]) Print(to[i]);
	}
	int cnt;
	void Build(int u) {
		// printf("%d\n",u);
		bool fl=0; sz[u]=0; ++cnt;
		for(int i=head[u];i;i=nxt[i]) {
			int v=to[i]; assert(v!=fa[u]);
			dep[v]=dep[u]+1;
			anc[v][0]=u;
			lim[v][0]=bd[u];
			Build(v);
			if(!fl) le[u]=le[v];
			sz[u]+=sz[v];
			fl=1;
		}
		if(!fl) assert(u<=n);
		if(u<=n) assert(!fl);
		if(!fl) {le[u]=u; t_s[u]=++ind; s_t[ind]=u; sz[u]=1;}
	}
	inline void Init(int rt) {
		lim[rt][0]=INF; dep[rt]=1;//ATT
		mem(lim,63);
		Build(rt); assert(cnt==all); assert(ind==n);
		for(int j=1;j<=lgN;j++)
			for(int i=1;i<=all;i++) {
				anc[i][j]=anc[anc[i][j-1]][j-1];
				lim[i][j]=lim[anc[i][j-1]][j-1];
			}
	}
	inline int Find(int u,int v) {
		for(int i=lgN;i>=0;i--) if(lim[u][i]<=v) u=anc[u][i];
		return u;
	}
}
namespace SEG {
	#define lc ch[u][0]
	#define rc ch[u][1]
	#define left lc,l,mid
	#define right rc,mid+1,r
	#define mid ((l+r)>>1)
	const int U=N*lgN;
	int rt[ALL],sz[U],ch[U][2],ind=1;
	inline int New_Node(int u) {
		sz[++ind]=sz[u];
		ch[ind][0]=ch[u][0]; ch[ind][1]=ch[u][1];
		return ind;
	}
	void Modify(int &u,int l,int r,int x) {
		// printf("%d %d %d %d\n",u,l,r,x);
		u=New_Node(u);
		if(l==r) {
			if(l!=x) cerr<<x<<endl;
			assert(l==x);
			++sz[u]; return;
		}
		if(x<=mid) Modify(left,x);
		if(x> mid) Modify(right,x);
		sz[u]=sz[lc]+sz[rc];
	}
	int Query(int u1,int u2,int l,int r,int k) {
		if(l==r) return l;
		int szl=sz[ch[u2][0]]-sz[ch[u1][0]];
		// printf("%d %d %d %d %d\n",u1,u2,szl,l,r);
		if(szl<k) return Query(ch[u1][1],ch[u2][1],mid+1,r,k-szl);
		else return Query(ch[u1][0],ch[u2][0],l,mid,k);
	}
	inline void Init() {
		for(int i=1;i<=n;i++) {
			rt[i]=rt[i-1];
			// printf("%d\n",s_t[i]);
			Modify(rt[i],1,n,h[s_t[i]]);
			// printf("%d\n",sz[rt[i]]);
		}
		// printf("rt\n"); for(int i=1;i<=n;i++) printf("%d ",rt[i]); puts("");
	}
}
map<int,int> key;
int _key[N];
int num[N],tot;
signed main() {
	// freopen("4.in","r",stdin);
	// freopen("my.out","w",stdout);
	read(n); read(m); read(q); tot=n;
	for(int i=1;i<=n;i++) read(h[i]),num[i]=h[i];
	sort(num+1,num+n+1); tot=unique(num+1,num+tot+1)-num-1;
	for(int i=tot;i>=1;i--) key[num[i]]=tot-i+1,_key[tot-i+1]=num[i];//reverse
	for(int i=1;i<=n;i++) h[i]=key[h[i]],assert(h[i]!=0);
	for(int i=1;i<=m;i++) KRU::e[i].in();
	
	all=rt=KRU::Kruskal(); TREE::Init(rt); SEG::Init();
	int ans=0;
	while(q--) {
		int u,v,k; read(u); read(v); read(k);
		u^=ans; v^=ans; k^=ans;
		u=TREE::Find(u,v); 
		// cerr<<'u'<<u<<"BD::"<<TREE::lim[u][0]<<" "<<v<<endl;
		if(TREE::sz[u]<k) ans=0,puts("-1");
		else {
			ans=SEG::Query(SEG::rt[t_s[le[u]]-1],SEG::rt[t_s[le[u]]+TREE::sz[u]-1],1,n,k);
			printf("%d\n",ans=_key[ans]);
		}
	}
	return 0;
}
/*
10 11 4
1 2 3 4 5 6 7 8 9 10
1 4 4
2 5 3
9 8 2
7 8 10
7 1 4
6 7 1
6 4 8
2 1 5
10 8 10
3 4 7
3 4 6
1 5 2
1 5 6
1 5 8
8 9 2
*/

用时:1.5h

posted @ 2018-08-18 19:07  functionendless  阅读(175)  评论(0编辑  收藏  举报