[CTSC2008]网络管理

[CTSC2008]网络管理

这个题看到维护链上路径,看起来很像是树剖,但是用线段树+树链剖分显然还要二分答案,这就三个log了,于是考虑复杂度更加优秀的做法.
线段树套树状数组(带修改主席树),主席树有道经典的板子题.Dynamic Rankings
那个是区间,这个是树上路径,其实大同小异.根据树的dfn序列,建线段树.
你做修改的时候,相当于把dfn序列中([dfn[x],dfn[x]+sz[x]-1])之间的点修改了嘛.
想象一下一排一模一样整齐的二叉树,优美地排列在你面前,这个时候一下把这些线段树们都压在一坨,每个二叉树的节点都开一个树状数组来维护前缀和.,然后你在这颗棵压扁的线段树上,没走到一个节点,就把这个节点的那个树状数组拿出来,查询或者修改你要的信息.
这样空间复杂度看起来是(n^2)的,所以显然要动态开点,树状数组也要动态开点.
注意树上单点修改是区间修改,所以树状数组是差分了的,单点查询相当于前缀和查询.
还有就是一定要离散化你的权值.

又臭又长的代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 80005
#define mid ((l+r)>>1)
using namespace std;
int n,m,tim,p,tot,Q,cnt1,cnt0,sz;
int seq[maxn],b[maxn<<1],s[maxn*400],lc[maxn*400],rc[maxn*400];
int tmp[2][maxn],dep[maxn],dfn[maxn],fa[maxn][20],size[maxn],rt[maxn];
struct node{int k,a,b;}q[maxn];
int head[maxn],nxt[maxn<<1],to[maxn<<1],cnt;
void add(int u,int v){nxt[++cnt]=head[u];head[u]=cnt;to[cnt]=v;}
inline int lowbit(int x){return x&-x;}
void update(int &x,int l,int r,int pos,int v)
{
	if(!x)x=++p;s[x]+=v;if(l==r)return;
	if(pos<=mid)update(lc[x],l,mid,pos,v);
	else update(rc[x],mid+1,r,pos,v);
}
int query(int l,int r,int k)//树状数组的log个点暴力在线段树上跳
{
	if(l==r)return l;int sum=0;
	for(int i=1;i<=cnt0;i++)sum+=s[lc[tmp[0][i]]];
	for(int i=1;i<=cnt1;i++)sum-=s[lc[tmp[1][i]]];
	if(k<=sum)
	{
		for(int i=1;i<=cnt0;i++)tmp[0][i]=lc[tmp[0][i]];
		for(int i=1;i<=cnt1;i++)tmp[1][i]=lc[tmp[1][i]];
		return query(l,mid,k);
	}
	else
	{
		for(int i=1;i<=cnt0;i++)tmp[0][i]=rc[tmp[0][i]];
		for(int i=1;i<=cnt1;i++)tmp[1][i]=rc[tmp[1][i]];
		return query(mid+1,r,k-sum);
	}
}
void dfs(int u,int ff)
{
	fa[u][0]=ff;dep[u]=dep[ff]+1;dfn[u]=++tim;size[u]=1;
	for(int i=1;i<=17;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i=head[u];i;i=nxt[i])
	{
		int v=to[i];if(v==ff)continue;
		dfs(v,u);size[u]+=size[v];
	}
}
int getlca(int x,int y)
{
	if(dep[x]<dep[y])swap(x,y);
	int tt=dep[x]-dep[y];
	for(int i=0;i<=17;i++)
		if(tt&(1<<i))x=fa[x][i];
	if(x==y)return x;
	for(int i=17;i>=0;i--)
		if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
void init()
{
	cin>>n>>Q;
	for(int i=1;i<=n;i++)scanf("%d",&seq[i]),b[++tot]=seq[i];
	for(int i=1,u,v;i<n;i++)scanf("%d%d",&u,&v),add(u,v),add(v,u);
	for(int i=1;i<=Q;i++)
	{
		scanf("%d%d%d",&q[i].k,&q[i].a,&q[i].b);
		if(!q[i].k)b[++tot]=q[i].b;
	}
	sort(b+1,b+1+tot);sz=unique(b+1,b+1+tot)-b-1;
	for(int i=1;i<=n;i++)seq[i]=lower_bound(b+1,b+1+sz,seq[i])-b;
	dfs(1,0);
	for(int i=1;i<=n;i++)
	{
		for(int j=dfn[i];j<=n;j+=lowbit(j))
			update(rt[j],1,sz,seq[i],1);
		for(int j=dfn[i]+size[i];j<=n;j+=lowbit(j))
			update(rt[j],1,sz,seq[i],-1);
	}
}
int main()
{
	init();
	for(int i=1,x,y;i<=Q;i++)
	{
		x=q[i].a;y=q[i].b;
		if(q[i].k)
		{
			int lca=getlca(x,y),fl=fa[lca][0],len;cnt0=cnt1=0;
			len=dep[x]+dep[y]-dep[lca]-dep[fl];
			for(int j=dfn[x];j>=1;j-=lowbit(j))tmp[0][++cnt0]=rt[j];
			for(int j=dfn[y];j>=1;j-=lowbit(j))tmp[0][++cnt0]=rt[j];
			for(int j=dfn[lca];j>=1;j-=lowbit(j))tmp[1][++cnt1]=rt[j];
			for(int j=dfn[fl];j>=1;j-=lowbit(j))tmp[1][++cnt1]=rt[j];
			if(q[i].k>len)puts("invalid request!");
			else printf("%d
",b[query(1,sz,len-q[i].k+1)]);
			
		}
		else
		{
			for(int j=dfn[x];j<=n;j+=lowbit(j))
				update(rt[j],1,sz,seq[x],-1);
			for(int j=dfn[x]+size[x];j<=n;j+=lowbit(j))
				update(rt[j],1,sz,seq[x],1);
			seq[x]=lower_bound(b+1,b+1+sz,y)-b;
			for(int j=dfn[x];j<=n;j+=lowbit(j))
				update(rt[j],1,sz,seq[x],1);
			for(int j=dfn[x]+size[x];j<=n;j+=lowbit(j))
				update(rt[j],1,sz,seq[x],-1);
		}
	}
	return 0;
}

原文地址:https://www.cnblogs.com/terribleterrible/p/9827550.html