BZOJ 3551: [ONTAK2010]Peaks加强版(可持久化线段树合并)

130 篇文章 1 订阅
124 篇文章 0 订阅

题目
求出克鲁斯卡尔树然后在子树内在线求第k大。
用主席树。
发现父亲的主席树是由两个子树的主席树合并而来。
可以写可持久化线段树合并。
感觉除了不回收儿子节点以外没啥区别。
用了一次fwrite,不好用。
一次不用fread,TLE到死。

#include<bits/stdc++.h>
#define maxn 200005
#define maxpt maxn*30
#define lim 20
using namespace std;

char cb[1<<18],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
void read(int &res){
	char ch;
	for(;!isdigit(ch=getc()););
	for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
}

char pb[1<<18],*pt=pb;
void Push(const char c){
	if(pt-pb==(1<<18)) fwrite(pb,1,1<<18,stdout),pt=pb;
	*pt++ = c;
}
void write(int res){
	static int sta[20];
	if(!res) Push('0');
	if(res<0) res = -res,Push('-');
	for(sta[0]=0;res;res/=10) sta[++sta[0]] = res % 10;
	for(;sta[0];)Push(sta[sta[0]--]+'0');
}

int rt[maxn],lc[maxpt],rc[maxpt],siz[maxpt],tot;
int n,m,q,h[maxn],sb[maxn],cnt_p;

void Insert(int &now,int l,int r,int pos){
	siz[++tot] = siz[now] + 1 , lc[tot] = lc[now] , rc[tot] = rc[now];
	now = tot;
	if(l == r) return;
 	int mid = (l+r) >> 1;
	if(pos <= mid) Insert(lc[now],l,mid,pos);
	else Insert(rc[now],mid+1,r,pos);
}

void Merge(int &now,int x,int y){
	//printf("%d %d %d\n",now,x,y);
	if(!x || !y) now = x+y;
	else {
		siz[now = ++tot] = siz[x] + siz[y];
		Merge(lc[now],lc[x],lc[y]);
		Merge(rc[now],rc[x],rc[y]);
	}
}

int Query(int now,int l,int r,int K){
	if(l == r) return l;
	int mid = (l+r) >> 1;
	if(siz[rc[now]] >= K) return Query(rc[now],mid+1,r,K);
	return Query(lc[now],l,mid,K-siz[rc[now]]);
}

struct edge{
	int u,v,w;
}e[3*maxn];
int c[maxn*3];
bool cmp(const int &u,const int &v){ return e[u].w == e[v].w ? e[u].u == e[v].u ? e[u].v < e[v].v : e[u].u < e[v].u : e[u].w < e[v].w; }

int F[maxn],val[maxn],f[lim][maxn];
int Find(int now){ return !F[now] ? now : F[now] = Find(F[now]); }

int main(){
//	int t1 = clock();
//	freopen("1.in","r",stdin);
//	freopen("1.out","w",stdout);
	read(n),read(m),read(q);cnt_p=n;
	for(int i=1;i<=n;i++){
		read(h[i]);
		sb[++sb[0]] = h[i];
	}
	sort(sb+1,sb+1+sb[0]);
	sb[0] = unique(sb+1,sb+1+sb[0])-sb-1;
	for(int i=1;i<=n;i++) 
		h[i]=lower_bound(sb+1,sb+1+sb[0],h[i])-sb,Insert(rt[i],1,sb[0],h[i]);
	for(int i=1;i<=m;i++){
		read(e[i].u),read(e[i].v),read(e[i].w);
		c[i] = i;
	}
	sort(c+1,c+1+m,cmp);
	for(int i=1;i<=m;i++)
		if(Find(e[c[i]].u) != Find(e[c[i]].v)){
			int up = Find(e[c[i]].u) , vp = Find(e[c[i]].v);
			Merge(rt[++cnt_p],rt[up],rt[vp]);
			f[0][up] = F[up] = f[0][vp] = F[vp] = cnt_p;
			val[cnt_p] = e[c[i]].w;
		}
	//for(int i=1;i<=cnt_p;i++)
		//printf("##%d\n",f[0][i]);
	for(int j=1;j<lim;j++)
		for(int i=1;i<=cnt_p;i++)
			f[j][i] = f[j-1][f[j-1][i]];
	for(int v,x,k,la=0;q--;){
		read(v),read(x),read(k);
		la = max(la , 0);
		//printf("%d %d\n",v,x);
		v^=la,x^=la,k^=la;
		for(int i=lim-1;i>=0;i--){
		//	printf("@%d %d\n",f[i][v],val[f[i][v]]);
			if(f[i][v]!=0 && val[f[i][v]]<=x)
				v = f[i][v];
		}
		//printf("%d %d\n",v,val[v]);
		if(siz[rt[v]] < k) la = -1;
		else la = sb[Query(rt[v],1,sb[0],k)];
		write(la),Push('\n');
	}
	fwrite(pb,1,pt-pb,stdout);
//	freopen("CON","w",stdout);
//	printf("%d\n",clock()-t1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值