zoukankan      html  css  js  c++  java
  • 【BZOJ3551】【洛谷P4197】—Peaks加强版(Kruscal重构树+主席树)

    BZOJ传送门

    洛谷传送门(注意洛谷上并没有要求强制在线)

    这道题有毒吧

    洛谷ACAC,本机ACAC,然而BZOJBZOJ上莫名TLETLE??

    fuckfuck


    考虑到有多次询问瓶颈路
    我们构建KruscalKruscal重构树

    由于重构树特殊的性质
    树上一个点的子树的权值必定都是比这个点小的

    那么对于每次询问的vv,我们考虑找到它到根路径上第一个权值大于等于xx的点
    这个可以用树上倍增实现

    那现在的问题就变成了在一个点的子树中,查询所有叶子节点的第kk
    这个对于dfsdfs序中叶子节点建主席树就解决了

    虽然感觉实现有点难写

    不过有个小技巧:我们可以发现重构树上每个非叶节点必定有2个儿子

    那么我们可以直接对每个点维护左右儿子,就不需要建邻接表

    具体细节可以看代码(丑到窒息)

    还有重构树可能是不连通的

    这个情况要判断

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	char ch=getchar();
    	int res=0,f=1;
    	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    	return res*f;
    }
    const int N=500005;
    const int M=1000005;
    const int Log=22;
    int n,m,q,h[N],s[N],ans=-1;
    namespace Kruscal{
    	struct edge{
    		int u,v,w;
    	}e[N];
    	int adj[N<<1],nxt[M<<2],to[M<<2],val[N<<1],tot,cnt,lc[N<<1],rc[N<<1],f[N<<1][Log],fa[N];
    	inline bool comp(const edge &a,const edge &b){
    		return a.w<b.w;
    	}
    	inline void addedge(int u,int v){
    		nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
    	}
    	int find(int x){
    		return fa[x]==x?x:fa[x]=find(fa[x]);
    	}
    	inline void kruscal(){
    		sort(e+1,e+m+1,comp);
    		for(int i=1;i<=m;i++){
    			int f1=find(e[i].u),f2=find(e[i].v);
    			if(f1!=f2){
    				fa[f1]=fa[f2]=fa[++tot]=tot;
    				f[f1][0]=f[f2][0]=tot;
    				lc[tot]=f1,rc[tot]=f2;
    				val[tot]=e[i].w;
    			}
    		}
    	}
    }
    namespace JZMS_Tree{
    	#define mid ((l+r)>>1)
    	#define lc(u) son[u][0]
    	#define rc(u) son[u][1]
    	int rt[N<<3],sum[7000000],num,son[7000000][2];
    	void insert(int &u,int r1,int l,int r,int pos){
    		u=++num;
    		sum[u]=sum[r1]+1;
    		if(l==r)return;
    		lc(u)=lc(r1),rc(u)=rc(r1);
    		if(pos<=mid)insert(lc(u),lc(r1),l,mid,pos);
    		else insert(rc(u),rc(r1),mid+1,r,pos);
    	}
    	int query(int r1,int r2,int l,int r,int k){
    		if(l==r)return s[l];
    		int t=sum[rc(r1)]-sum[rc(r2)];
    		if(t>=k)return query(rc(r1),rc(r2),mid+1,r,k);
    		else return query(lc(r1),lc(r2),l,mid,k-t);
    	}
    	#undef lc
    	#undef rc
    }
    namespace Pre_operator{
    	using namespace Kruscal;
    	using namespace JZMS_Tree;
    	int in[N<<1],out[N<<1];
    	int dfn;
    	void dfs(int u){
    		for(int i=1;i<=20;i++)
    			f[u][i]=f[f[u][i-1]][i-1];
    		if(u<=n){
    			in[u]=out[u]=++dfn;
    			insert(rt[dfn],rt[dfn-1],1,n,h[u]);
    			return;
    		}
    		dfs(lc[u]),dfs(rc[u]);
    		in[u]=in[lc[u]],out[u]=out[rc[u]];
    	}
    	int get(int u,int k){
    		for(int i=20;i>=0;i--){
    			if(f[u][i]&&val[f[u][i]]<=k)
    				u=f[u][i];
    		}
    		return u;
    	}
    }
    using namespace Pre_operator;
    int main(){
    	tot=n=read(),m=read(),q=read();
    	for(int i=1;i<=n;i++)h[i]=s[i]=read();
    	sort(s+1,s+n+1);
    	for(int i=1;i<=n;i++)
    		h[i]=lower_bound(s+1,s+n+1,h[i])-s;
    	for(int i=1;i<=m;i++){
    		e[i].u=read(),e[i].v=read(),e[i].w=read();
    	}
    	for(int i=1;i<=n;i++)fa[i]=i;
    	kruscal();
    	for(int i=tot;i;i--)
    	if(!in[i])dfs(i);
    	dfs(find(1));
    	for(int i=1;i<=q;i++){
    		int v=read(),x=read(),k=read();
    		if(ans!=-1)v^=ans,x^=ans,k^=ans;
    		v=get(v,x);
    		if(out[v]-in[v]+1<k)ans=-1;
    		else ans=query(rt[out[v]],rt[in[v]-1],1,n,k);
    		cout<<ans<<'
    ';
    	}
    }
    
  • 相关阅读:
    @topcoder
    @uoj
    Vue-路由跳转的几种方式和路由重定向
    Vue-设置默认路由选中
    Vue-使用webpack+vue-cli搭建项目
    Vue-状态管理Vuex的使用
    Vue-全局变量和方法
    JS-apply、call、bind
    CSS-禁止文本被选中
    Vue-路由模式 hash 和 history
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/10366328.html
Copyright © 2011-2022 走看看