【树链剖分】【bzoj 1146】: [CTSC2008]网络管理Network

http://www.lydsy.com/JudgeOnline/problem.php?id=1146


以前看来是一道神题,今天终于A了


二分+树链剖分+树套树 4个log 2333333

由于写得非常模块化,所以代码写起来有点长,但是写完了只改了两个地方!!!

除了模板部分习惯性缩了行,其余没有缩行,但tmTreap的del函数都写错了,真是该死

蒟蒻太懒没有离散化所以慢了点

思路写得很清晰,以后写主席树

我貌似很落后诶、、、


//#define _TEST _TEST
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
/************************************************
Code By willinglive    Blog:http://willinglive.cf
************************************************/
#define rep(i,l,r) for(int i=(l),___t=(r);i<=___t;i++)
#define per(i,r,l) for(int i=(r),___t=(l);i>=___t;i--)
#define MS(arr,x) memset(arr,x,sizeof(arr))
#define LL long long
#define INE(i,u,e) for(int i=head[u];~i;i=e[i].next)
inline const int read()
{int r=0,k=1;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')k=-1;
for(;c>='0'&&c<='9';c=getchar())r=r*10+c-'0';return k*r;}
/
const int N=80008;
int n,q;
inline int rnd(){return rand()<<16|rand();}
/
namespace Tree
{         //
int T[N];
struct edge{int v,w,next;}e[N*2];
int head[N],k;
void adde(int u,int v){e[k].v=v;e[k].next=head[u];head[u]=k++;}

int sz[N],fa[N],son[N],dep[N];
int top[N],id[N],cnt;
}          ///
namespace Treap
{          ///
#define LS T[o].l
#define RS T[o].r
struct node{int l,r,s,cnt,rnd,x;}T[4000000];
int sz;
void update(int o){T[o].s=T[LS].s+T[RS].s+T[o].cnt;}
void l_rot(int &o){int t=RS;RS=T[t].l;T[t].l=o;T[t].s=T[o].s;update(o);o=t;}
void r_rot(int &o){int t=LS;LS=T[t].r;T[t].r=o;T[t].s=T[o].s;update(o);o=t;}
void insert(int &o,int x)
{
	if(!o)
	{
		o=++sz; T[o].l=T[o].r=0; T[o].s=T[o].cnt=1; T[o].x=x; T[o].rnd=rnd();
		return;
	}
	T[o].s++;
	if(x<T[o].x)
	{
		insert(LS,x);
		if(T[LS].rnd<T[o].rnd) r_rot(o);
	}
	else if(x>T[o].x)
	{
		insert(RS,x);
		if(T[RS].rnd<T[o].rnd) l_rot(o);
	}
	else T[o].cnt++;
}
void del(int &o,int x)
{
	if(!o) return;
	if(T[o].x==x)
	{
		if(T[o].cnt>1) T[o].cnt--,T[o].s--;
		else if(LS==0||RS==0) o=LS+RS;
		else if(T[LS].rnd<T[RS].rnd) r_rot(o),del(o,x);
		else l_rot(o),del(o,x);
		return;
	}
	T[o].s--;
	if(x<T[o].x) del(LS,x);
	else del(RS,x);
}
int getrank(int o,int x)//>=x
{
	if(!o) return 0;
	if(x<T[o].x) return T[RS].s+T[o].cnt+getrank(LS,x);
	else if(x>T[o].x) return getrank(RS,x);
	else return T[RS].s+T[o].cnt;
}
#undef LS
#undef RS
}          ///
namespace SGT
{          //
#define LS o<<1,L,mid
#define RS o<<1|1,mid+1,R
int root[300000],tot;
int id_1[N];
void build(int o,int L,int R)
{
	rep(i,L,R) Treap::insert(root[o],Tree::T[id_1[i]]);
	if(L==R) return;
	int mid=L+R>>1;
	build(LS); build(RS);
}
void modify(int pos,int x,int o,int L,int R)
{
	Treap::del(root[o],Tree::T[id_1[pos]]);
	Treap::insert(root[o],x);
	if(L==R) return;
	int mid=L+R>>1;
	if(pos<=mid) modify(pos,x,LS);
	else modify(pos,x,RS);
}
int getrank(int x,int l,int r,int o,int L,int R)
{
	if(l<=L && R<=r)
	{
		return Treap::getrank(root[o],x);
	}
	int mid=L+R>>1;
	if(r<=mid) return getrank(x,l,r,LS);
	else if(l>mid) return getrank(x,l,r,RS);
	else return getrank(x,l,mid,LS)+getrank(x,mid+1,r,RS);
}
}         ///
namespace Tree
{        //
void dfs1(int u)
{
	sz[u]=1; son[u]=0;
	INE(i,u,e)
	{
		int v=e[i].v; if(v==fa[u]) continue;
		fa[v]=u; dep[v]=dep[u]+1;
		dfs1(v);
		sz[u]+=sz[v];
		if(sz[v]>sz[son[u]]) son[u]=v;
	}
}
void dfs2(int u,int tp)
{
	top[u]=tp; id[u]=++cnt;
	if(son[u]) dfs2(son[u],tp);
	INE(i,u,e)
	{
		int v=e[i].v; if(v==fa[u]||v==son[u]) continue;
		dfs2(v,v);
	}
}
void init()
{
	using namespace SGT;
	dfs1(1); dfs2(1,1);
	rep(i,1,n) id_1[id[i]]=i;
	build(1,1,n);
}
inline void modify(int u,int x)
{
	SGT::modify(id[u],x,1,1,cnt);
	T[u]=x;
}
int getrank(int a,int b,int x)
{
	int ta=top[a],tb=top[b];
	int ans=0;
	while(ta^tb)
	{
		if(dep[ta]<dep[tb]) swap(a,b),swap(ta,tb);
		ans+=SGT::getrank(x,id[ta],id[a],1,1,cnt);
		a=fa[ta]; ta=top[a];
	}
	if(dep[a]>dep[b]) swap(a,b);
	return ans+SGT::getrank(x,id[a],id[b],1,1,cnt);
}
int query(int a,int b,int k)
{
	if(getrank(a,b,0)<k) return -1;
	int l=0,r=100000000,mid;
	while(l<r)
	{
		mid=l+r+1>>1;
		if(getrank(a,b,mid)<k) r=mid-1;
		else l=mid;
	}
	return l;
}
}        ///
/
void input()
{
	using namespace Tree;
	MS(head,-1);
    n=read(); q=read();
    rep(i,1,n) T[i]=read();
    int u,v;
    rep(i,1,n-1)
    {
    	u=read(); v=read(); 
    	adde(u,v); adde(v,u);
    }
}
void solve()
{
	using namespace Tree;
	int k,a,b;
	init();
	while(q--)
	{
		k=read(); a=read(); b=read();
		if(!k)
		{
			modify(a,b);
		}
		else
		{
			int ret=query(a,b,k);
			if(ret!=-1) printf("%d\n",query(a,b,k));
			else puts("invalid request!");
		}
	}
}
/
int main()
{
    #ifndef _TEST
    freopen("std.in","r",stdin); freopen("std.out","w",stdout);
    #endif
    input(),solve();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值