花花的礼物 (huahua)

 

from dtoj 1936

题意

花花是个爱动脑子的孩子,在她的生日的时候,她的爸爸给她准备了个礼物。但是,她的爸爸并不想让她轻易得到礼物,他把礼物放在了一个箱子里面,只有输入正确的密码才能打开箱子,而她的爸爸告诉了她这个礼物该怎么得到:
他们所在的城市可以看成有 nnn 个点, mmm 条边的无向图,每个点上有一个权值 aia_iai,每条边有一个权值 www
我们定义两个点 xxxyyy 关于 kkk 联通当且仅当存在一条从 xxxyyy 的路径,满足这条路径上的 www 的最大值小于等于 kkk
而密码就是和节点 xxx 关于 kkk 联通的所有节点的 aia_iai 构成的集合 BBBsummexsummexsummex
我们定义一个可重复数集 BBBsummexsummexsummex 为无法用 BBB 集合的子集的和表示的正整数的最小值。
例如,B={1,1,3,7}B=\{1,1,3,7\}B={1,1,3,7} ,他能表示 0{}0\{\}0{}1{1}1\{1\}1{1}2{1,1}2\{1,1\}2{1,1}3{3}3\{3\}3{3}4{1+3}4\{1+3\}4{1+3}5{1+1+3}5\{1+1+3\}5{1+1+3} ,但是他不能表示 666 ,所以 summex{1,1,3,7}summex\{1, 1, 3, 7\}summex{1,1,3,7}666
由于她的爸爸有点健忘,他可能会记错,所以会有多组( QQQ 组)询问。对于每组询问,你都要给一个正确的答案。
为了提高难度,我们会对数据加密,对于一个给定的数 SSS ,解密输入中的C++代码是:

inline void decode(int &x, int &y){
	x = (lstans & S) ^ x;
	y = (lstans & S) ^ y;
}

其中的 lstanslstanslstans 是上次询问的答案。
在这里插入图片描述

题解

考虑离线的做法
按照 kkk 排序,每个点当做一棵线段树,做最小生成树的时候,把边权 &lt;=k&lt;=k<=k 的边连接,并且线段树合并到根上,然后按照神秘数的做法找出 ansansans 即可
(到时候再补神秘数的题解
考虑在线作法,把 KruskalKruskalKruskal 重构树建出,然后每个点开一棵线段树,然后往根合并上去,查询的时候倍增找到其路径上第一个点权 &lt;=k&lt;=k<=k 的线段树,按照神秘数的做法即可
(注意原来的边有 5e55e55e5 条(一开始别的都对了,然后被这个坑了一晚上:(
上代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=2e5+5;LL s[N*20],ans;
int head[N],V[N],nex[N],b[N],B,tt;
int n,m,Q,S,a[N],tot,t,w[N],f[N];
int ls[N*20],rs[N*20],T[N],fa[N][20];
struct O{int x,y,z;}p[500005];
bool cmp(O A,O B){return A.z<B.z;}
int get(int x){
	return x==f[x]?x:f[x]=get(f[x]);
}
inline void add(int u,int v){
	V[++t]=v;nex[t]=head[u];head[u]=t;
}
#define d ((l+r)>>1)
void ins(int& x,int l,int r,int v){
	x=++tt;s[x]=v;if (l==r) return;
	if (v<=b[d]) ins(ls[x],l,d,v);
	else ins(rs[x],d+1,r,v);
}
int update(int x1,int x2){
	if (!x1 || !x2) return x1+x2;
	int x=++tt;s[x]=s[x1]+s[x2];
	ls[x]=update(ls[x1],ls[x2]);
	rs[x]=update(rs[x1],rs[x2]);
	return x;
}
LL query(int x,int l,int r,LL v){
	if (!x) return 0ll;
	if (l==r) return (LL)b[l]>v?0ll:s[x];
	if (b[d]>=v) return query(ls[x],l,d,v);
	return s[ls[x]]+query(rs[x],d+1,r,v);
}
void dfs(int x){
	for (int i=1;fa[fa[x][i-1]][i-1];i++)
		fa[x][i]=fa[fa[x][i-1]][i-1];
	for (int i=head[x];i;i=nex[i])
		fa[V[i]][0]=x,dfs(V[i]);
}
int main(){
	scanf("%d%d%d%d",&n,&m,&Q,&S);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]),b[i]=a[i];
	sort(b+1,b+n+1);B=unique(b+1,b+n+1)-b-1;
	for (int i=1;i<=m;i++)
		scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z);
	sort(p+1,p+m+1,cmp);tot=n;
	for (int i=1;i<=n;i++) ins(T[i],1,B,a[i]);
	for (int i=1;i<n+n;i++) f[i]=i;
	for (int x,y,i=1;i<=m;i++){
		x=get(p[i].x),y=get(p[i].y);
		if (x==y) continue;
		w[++tot]=p[i].z;add(tot,x);add(tot,y);
		f[x]=tot;f[y]=tot;T[tot]=update(T[x],T[y]);
	}
	for (int i=1;i<=tot;i++) if (f[i]==i) dfs(i);
	for (int x,k;Q--;printf("%lld\n",ans)){
		scanf("%d%d",&x,&k);
		x=(ans&S)^x;k=(ans&S)^k;
		for (int i=19;~i;i--)
			if (fa[x][i] && w[fa[x][i]]<=k)
				x=fa[x][i];
		ans=1;LL p;while(1){
			p=query(T[x],1,B,ans);
			if (p>=ans) ans=p+1;else break;
		}
	}
	return 0;
}
posted @ 2019-02-24 21:47  xjqxjq  阅读(248)  评论(0编辑  收藏  举报