Codechef:Count on a Treap(线段树)

传送门

题解:
Treap的中序遍历是按照键值来排序后的序列,两点的lca为这个序列上区间权值的最小值。

现在只用考虑怎么求深度:
显然往前的一个权值比他大的会成为他的父亲,或者他们中间夹了一个更大的成为他的父亲。 其实就是求上升序列,然后套用常见套路即可。

#include <bits/stdc++.h>
using namespace std;
typedef pair <int,int> pii;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&& (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}

const int N=3e5+50;
int n,m,pos[N],ori[N],a[N];
struct query {int op,p,q;} q[N];
map <int,int> mp;

inline void init() {
	n=rd();
	vector <pii> vec;
	for(int i=1;i<=n;i++) {
		int op=rd();
		if(op==0) {
			q[i].op=1; q[i].p=++m;
			pos[m]=rd(); a[m]=rd();
			vec.push_back(pii(pos[m],m));
		} else if(op==1) {
			q[i].op=2; q[i].p=rd();
		} else {
			q[i].op=3; q[i].p=rd(); q[i].q=rd();
		}
	}
	sort(vec.begin(),vec.end());
	for(int i=0;i<m;i++) ori[i+1]=pos[vec[i].second], pos[vec[i].second]=i+1;
}

struct node {
	pii mn;
	int l1,r1,len1;
	int l2,r2,len2;
	inline void init(int v) {
		mn=pii(v,0); 
		l1=r1=l2=r2=v;
		len1=len2=1;
	}
} tr[N*4];
inline int calcl(int k,int l,int r,int lim) {
	if(l==r) return tr[k].mn.first>lim;
	int mid=(l+r)>>1;
	if(tr[k].l1>lim) return tr[k].len1;
	else if(tr[k<<1|1].r1>lim) return tr[k].len1-tr[k<<1|1].len1+calcl(k<<1|1,mid+1,r,lim);
	else return calcl(k<<1,l,mid,lim);
}
inline int calcr(int k,int l,int r,int lim) {
	if(l==r) return tr[k].mn.first>lim;
	int mid=(l+r)>>1;
	if(tr[k].l2>lim) return tr[k].len2;
	else if(tr[k<<1].r2>lim) return tr[k].len2-tr[k<<1].len2+calcr(k<<1,l,mid,lim);
	else return calcr(k<<1|1,mid+1,r,lim);
}
inline void inc(int k,int l,int r,int p,int v) {
	if(l==r) {
		tr[k].init(v); 
		tr[k].mn.second=(v>=0) ? l : -1;
		return;
	} int mid=(l+r)>>1;
	if(p<=mid) inc(k<<1,l,mid,p,v);
	else inc(k<<1|1,mid+1,r,p,v);
	tr[k].mn=max(tr[k<<1].mn,tr[k<<1|1].mn);
	
	tr[k].l1=tr[k<<1|1].l1;
	tr[k].r1=max(tr[k<<1|1].r1,tr[k<<1].r1);
	tr[k].len1=tr[k<<1|1].len1+calcl(k<<1,l,mid,tr[k<<1|1].r1);
	
	tr[k].l2=tr[k<<1].l2;
	tr[k].r2=max(tr[k<<1].r2,tr[k<<1|1].r2);
	tr[k].len2=tr[k<<1].len2+calcr(k<<1|1,mid+1,r,tr[k<<1].r2);
}
inline int ql(int k,int l,int r,int L,int R,int &lim) {
	if(L>R) return 0;
	if(L<=l && r<=R) {
		int len=calcl(k,l,r,lim); 
		lim=max(lim,tr[k].r1);
		return len;
	} int mid=(l+r)>>1;
	if(R<=mid) return ql(k<<1,l,mid,L,R,lim);
	else if(L>mid) return ql(k<<1|1,mid+1,r,L,R,lim);
	else {
		int len=ql(k<<1|1,mid+1,r,L,R,lim);
		len+=ql(k<<1,l,mid,L,R,lim);
		return len;
	}
}
inline int qr(int k,int l,int r,int L,int R,int &lim) {
	if(L>R) return 0;
	if(L<=l && r<=R) {
		int len=calcr(k,l,r,lim);
		lim=max(lim,tr[k].r2);
		return len;
	} int mid=(l+r)>>1;
	if(R<=mid) return qr(k<<1,l,mid,L,R,lim);
	else if(L>mid) return qr(k<<1|1,mid+1,r,L,R,lim);
	else {
		int len=qr(k<<1,l,mid,L,R,lim);
		len+=qr(k<<1|1,mid+1,r,L,R,lim);
		return len;
	}
}
inline pii askmn(int k,int l,int r,int L,int R) {
	if(L<=l && r<=R) return tr[k].mn;
	int mid=(l+r)>>1;
	if(R<=mid) return askmn(k<<1,l,mid,L,R);
	else if(L>mid) return askmn(k<<1|1,mid+1,r,L,R);
	else return max(askmn(k<<1,l,mid,L,R),askmn(k<<1|1,mid+1,r,L,R));
}
inline int askdep(int x) {
	int val=askmn(1,1,m,x,x).first;
	int r=val, t1=ql(1,1,m,1,x-1,r);
	int l=val, t2=qr(1,1,m,x+1,m,l);
	return t1+t2+1;
}
int main() {
	init();
	for(int i=1;i<N;i++) tr[i].mn=pii(-1,-1);
	for(int i=1;i<=n;i++) {
		if(q[i].op==1) {
			inc(1,1,m,pos[q[i].p],a[q[i].p]);
			mp[ori[pos[q[i].p]]]=pos[q[i].p];
		} else if(q[i].op==2) {
			inc(1,1,m,mp[q[i].p],-1);
		} else {
			int l=mp[q[i].p], r=mp[q[i].q];
			if(l>r) swap(l,r);
			int lca=askmn(1,1,m,l,r).second;
			printf("%d\n",askdep(l)+askdep(r)-2*askdep(lca));
		}
	}
}
发布了557 篇原创文章 · 获赞 220 · 访问量 23万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览