联考20200718 T1 因懒无名

题目描述:


分析:
签到题想半天,人没了
将两个点集合并维护直径,两个点集分别的直径一共四个端点两两距离最大即为直径
区间点集合并,联想到线段树,每个区间两个值表示这个区间点集合并出的端点,简单维护
考虑颜色变化导致的点集内部插入删除
加入很好维护,删除不行
每种颜色动态开点线段树,依葫芦画瓢维护
巨佬们说可以直接一发平衡树,按颜色排序,支持插入删除,维护区间直径
好像Splay和非旋Treap都可以维护
也是可以做的,只不过我平衡树太菜了,写的动态开点
我的复杂度是\(O(nlog^2n)\),写了\(O(1)\)求LCA深度之后就可以减到\(O(nlogn)\)
(怎么我\(O(nlog^2n)\)比写\(O(nlogn)\)的平衡树快啊2333

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<string>

#define maxn 200005
#define INF 0x3f3f3f3f

using namespace std;

inline int getint()
{
	int num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,m,Q;
int fir[maxn],nxt[maxn<<1],to[maxn<<1],cnt;
int sz[maxn],fa[maxn],dpt[maxn],son[maxn],tp[maxn];
int C[maxn],rt[maxn],tot;
int lc[maxn<<6],rc[maxn<<6];

inline void newnode(int u,int v)
{to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
inline void dfs1(int u)
{
	sz[u]=1;
	for(int i=fir[u];i;i=nxt[i])if(to[i]!=fa[u])
	{
		fa[to[i]]=u,dpt[to[i]]=dpt[u]+1;
		dfs1(to[i]),sz[u]+=sz[to[i]];
		if(sz[son[u]]<sz[to[i]])son[u]=to[i];
	}
}
inline void dfs2(int u,int ac)
{
	tp[u]=ac;if(son[u])dfs2(son[u],ac);
	for(int i=fir[u];i;i=nxt[i])if(to[i]!=fa[u]&&to[i]!=son[u])dfs2(to[i],to[i]);
}
inline int LCA(int u,int v)
{
	while(tp[u]!=tp[v])
	{
		if(dpt[tp[u]]<dpt[tp[v]])swap(u,v);
		u=fa[tp[u]];
	}
	return dpt[u]<dpt[v]?u:v;
}
inline int getdis(int u,int v)
{return dpt[u]+dpt[v]-2*dpt[LCA(u,v)];}

struct node{
	int A,B;
	inline void pushup(node x,node y)
	{
		if(!x.A||!y.A){A=x.A|y.A,B=x.B|y.B;return;}
		int mx=-1,tmp;
		if((tmp=getdis(x.A,x.B))>mx)mx=tmp,A=x.A,B=x.B;
		if((tmp=getdis(y.A,y.B))>mx)mx=tmp,A=y.A,B=y.B;
		if((tmp=getdis(x.A,y.A))>mx)mx=tmp,A=x.A,B=y.A;
		if((tmp=getdis(x.A,y.B))>mx)mx=tmp,A=x.A,B=y.B;
		if((tmp=getdis(x.B,y.A))>mx)mx=tmp,A=x.B,B=y.A;
		if((tmp=getdis(x.B,y.B))>mx)mx=tmp,A=x.B,B=y.B;
	}
}t[maxn<<2],p[maxn<<6],Ans;

inline void insert(int &i,int l,int r,int x,int num)
{
	if(!i)i=++tot;
	if(l==r){p[i].A=p[i].B=num;return;}
	int mid=(l+r)>>1;
	if(x<=mid)insert(lc[i],l,mid,x,num);
	else insert(rc[i],mid+1,r,x,num);
	p[i].pushup(p[lc[i]],p[rc[i]]);
}
inline void build(int i,int l,int r)
{
	if(l==r){t[i]=p[rt[l]];return;}
	int mid=(l+r)>>1;
	build(i<<1,l,mid),build(i<<1|1,mid+1,r);
	t[i].pushup(t[i<<1],t[i<<1|1]);
}
inline void update(int i,int l,int r,int x)
{
	if(l==r){t[i]=p[rt[x]];return;}
	int mid=(l+r)>>1;
	if(x<=mid)update(i<<1,l,mid,x);
	else update(i<<1|1,mid+1,r,x);
	t[i].pushup(t[i<<1],t[i<<1|1]);
}
inline void query(int i,int l,int r,int ql,int qr)
{
	if(qr<l||r<ql)return;
	if(ql<=l&&r<=qr){Ans.pushup(Ans,t[i]);return;}
	int mid=(l+r)>>1;
	query(i<<1,l,mid,ql,qr),query(i<<1|1,mid+1,r,ql,qr);
}

int main()
{
	n=getint(),m=getint(),Q=getint();
	for(int i=1;i<=n;i++)C[i]=getint();
	for(int i=1;i<n;i++)
	{
		int u=getint(),v=getint();
		newnode(u,v),newnode(v,u);
	}
	dfs1(1),dfs2(1,1);
	for(int i=1;i<=n;i++)insert(rt[C[i]],1,n,i,i);
	build(1,1,m);
	while(Q--)
	{
		int op=getint(),x=getint(),y=getint();
		if(op==1)
		{
			insert(rt[C[x]],1,n,x,0);
			update(1,1,m,C[x]);
			C[x]=y;
			insert(rt[C[x]],1,n,x,x);
			update(1,1,m,C[x]);
		}
		else
		{
			Ans.A=Ans.B=0;
			query(1,1,m,x,y);
			printf("%d\n",Ans.A?getdis(Ans.A,Ans.B):0);
		}
	}
}

posted @ 2020-07-18 16:28  Izayoi_Doyo  阅读(197)  评论(0编辑  收藏  举报