zoukankan      html  css  js  c++  java
  • [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
    ",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('	'); printf("%d:%d %d
    ",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
    ",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
    ",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
    ",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
    ",s_t[i]);
    			Modify(rt[i],1,n,h[s_t[i]]);
    			// printf("%d
    ",sz[rt[i]]);
    		}
    		// printf("rt
    "); 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
    ",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

  • 相关阅读:
    韩式英语
    Daily dictation 听课笔记
    words with same pronunciation
    you will need to restart eclipse for the changes to take effect. would you like to restart now?
    glottal stop(britain fountain mountain)
    education 的发音
    第一次用Matlab 的lamada语句
    SVN的switch命令
    String的split
    SVN模型仓库中的资源从一个地方移动到另一个地方的办法(很久才解决)
  • 原文地址:https://www.cnblogs.com/functionendless/p/9498283.html
Copyright © 2011-2022 走看看