1. 程式人生 > 實用技巧 >20200718聯考T1 因懶無名

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);
		}
	}
}