1. 程式人生 > 實用技巧 >洛谷 U136100 貝爾jia的惡作劇

洛谷 U136100 貝爾jia的惡作劇

洛谷 U136100 貝爾jia的惡作劇

洛谷傳送門

題目背景

眾所周知,\(Rose\)家的貝爾jia是一隻喜歡惡作劇的色貓。

題目描述

這天,它翻到了\(Rose\)準備送給\(Seaway\)的禮物——樹枝燭臺。\(Rose\)早已把這個禮物做好,現在這個燭臺可以被看做是具有\(N\)個節點,\(N-1\)條邊的無根樹。當貝爾jia發現它之前,它的所有節點還保持著原來的顏色——綠色。

貝爾jia決定對這個禮物進行惡作劇,把這棵樹的一些節點塗成它最喜歡的顏色。因為它是隻色貓,所以它最喜歡的顏色是黃色。它每次塗色只塗一個節點,並且,如果它決定塗黃的節點已經被塗過黃色了,它會把這個節點重新還原成綠色。與此同時,它想要隨時瞭解到自己的惡作劇進行到哪步了。所以它會提出以下操作:

1 x代表把x點塗色(按上述規則)

2 x詢問從1到x這條路徑上最早出現的黃色節點編號

3 x y詢問從x到y這條路徑上的顏色段數量。

貝爾jia告訴你,極長的連續相同顏色被認為是一段。比如:yygggy由三段組成:yygggy

輸入格式

輸入的第一行是用空格隔開的兩個整數\(N,Q\),分別表示樹枝燭臺的節點數量和運算元量。接下來的\(N-1\)行,每行兩個整數,描述邊。接下來的\(Q\)行,每行描述一個操作。格式如題目描述所述。

輸出格式

回答每個2、3操作。

資料範圍

對於\(30\%\)的資料,\(1\le N,Q\le 1000\)

對於\(60\%\)的資料,\(1\le N,Q\le 10000\)

對於\(100\%\)的資料,\(1\le N,Q\le 100000\)


命題背景:

糅合了兩道題,都是樹上染色之後用樹剖架線段樹統計的。覺得很河狸,就自己出了一道。

打賭今年CSP或者NOIP會考

也練一下細節處理能力。

至於題目背景嘛,也是比較隨意地命完了,想到了貓咪,然後就想到了\(Rose\)家的那隻,呵呵。大色貓大色貓大色貓大色貓。

憤恨得我要出個題讓它千古流臭。


題解:

展示一下切題思路:

首先一看就知道,是樹剖。

考慮往上架線段樹。看起來兩個資訊都不太可拿線段樹來維護。所以這也是這道題的思維難度所在。

首先,第一個出現的黃色節點編號,可以考慮:我們可以把黃色點的權值就賦成它的樹剖序,綠色點的權值就賦成正無窮。那麼我們就可以把這個區間查詢轉化成區間最小值來處理啦!

細節是樹剖序、節點編號的轉化。

然後,維護顏色段。可以參考小白逛公園的維護方式,在維護答案的同時維護區間左右端點的顏色。顯然的是,在區間合併的時候,如果左兒子的右端點顏色等於右兒子的左端點顏色,那麼就需要把答案-1.

細節是鏈上跳躍的時候也要注意這個區間合併。因為詢問就是按鏈來的。

所以總程式碼:大約4K,用了10M空間,200MS以內跑過。所以空間只給了64MB,時間還是一秒,再壓就要被罵毒瘤了。

#include<cstdio>
#include<algorithm>
#define lson pos<<1
#define rson pos<<1|1
using namespace std;
const int maxn=1e5+10;
int n,m;
int a[maxn];
int tot,to[maxn<<1],head[maxn],nxt[maxn<<1];
int fa[maxn],deep[maxn],size[maxn],cnt,w[maxn],son[maxn],top[maxn],id[maxn];
int sum[maxn<<2],lc[maxn<<2],rc[maxn<<2],lazy[maxn<<2];
void add(int x,int y)
{
	to[++tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
}
void dfs1(int x,int f)
{
	deep[x]=deep[f]+1;
	fa[x]=f;
	size[x]=1;
	for(int i=head[x];i;i=nxt[i])
	{
		int y=to[i];
		if(y==f)
			continue;
		dfs1(y,x);
		size[x]+=size[y];
		if(!son[x]||size[y]>size[son[x]])
			son[x]=y;
	}
}
void dfs2(int x,int t)
{
	top[x]=t;
	id[x]=++cnt;
	w[cnt]=a[x];
	if(!son[x])
		return;
	dfs2(son[x],t);
	for(int i=head[x];i;i=nxt[i])
	{
		int y=to[i];
		if(y==fa[x]||y==son[x])
			continue;
		dfs2(y,y);
	}
}
void pushup(int pos)
{
	sum[pos]=(rc[lson]==lc[rson])?(sum[lson]+sum[rson]-1):(sum[lson]+sum[rson]);
	lc[pos]=lc[lson];
	rc[pos]=rc[rson];
}
void build(int pos,int l,int r)
{
	int mid=(l+r)>>1;
	if(l==r)
	{
		sum[pos]=1;
		lc[pos]=rc[pos]=w[l];
		return;
	}
	build(lson,l,mid);
	build(rson,mid+1,r);
	pushup(pos);
}
void mark(int pos,int l,int r,int k)
{
	lazy[pos]=k;
	sum[pos]=1;
	lc[pos]=rc[pos]=k;
}
void pushdown(int pos,int l,int r)
{
	int mid=(l+r)>>1;
	mark(lson,l,mid,lazy[pos]);
	mark(rson,mid+1,r,lazy[pos]);
	lazy[pos]=0;
}
void update(int pos,int l,int r,int x,int y,int k)
{
	int mid=(l+r)>>1;
	if(x<=l && r<=y)
	{
		mark(pos,l,r,k);
		return;
	}
	if(lazy[pos])
		pushdown(pos,l,r);
	if(y<=mid)
		update(lson,l,mid,x,y,k);
	else if(x>mid)
		update(rson,mid+1,r,x,y,k);
	else
	{
		update(lson,l,mid,x,y,k);
		update(rson,mid+1,r,x,y,k);
	}
	pushup(pos);
}
int query(int pos,int l,int r,int x,int y)
{
	int mid=(l+r)>>1;
	if(x<=l && r<=y)
		return sum[pos];
	if(lazy[pos])
		pushdown(pos,l,r);
	if(y<=mid)
		query(lson,l,mid,x,y);
	else if(x>mid)
		query(rson,mid+1,r,x,y);
	else
	{
		int ret=query(lson,l,mid,x,y)+query(rson,mid+1,r,x,y);
		if(lc[rson]==rc[lson])
			ret--;
		return ret;
	}
}
void upd(int x,int y,int k)
{
	while(top[x]!=top[y])
	{
		if(deep[top[x]]<deep[top[y]])
			swap(x,y);
		update(1,1,n,id[top[x]],id[x],k);
		x=fa[top[x]];
	}
	if(deep[x]<deep[y])
		swap(x,y);
	update(1,1,n,id[y],id[x],k);
}
int q(int x,int y)
{
	int ret=0;
	int last=0;
	while(top[x]!=top[y])
	{
		if(deep[top[x]]<deep[top[y]])
			swap(x,y);
		ret+=query(1,1,n,id[top[x]],id[x]);
		if(last==w[id[top[x]]])
			ret--;
		last=w[id[x]];
		x=fa[top[x]];
	}
	if(deep[x]<deep[y])
		swap(x,y);
	ret+=query(1,1,n,id[y],id[x]);
	if()
	return ret;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	dfs1(1,0);
	dfs2(1,1);
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		char opt[3];
		int a,b,c;
		scanf("%s",opt);
		if(opt[0]=='C')
		{
			scanf("%d%d%d",&a,&b,&c);
			upd(a,b,c);
		}
		else
		{
			scanf("%d%d",&a,&b);
			printf("%d\n",q(a,b));
		}
	}
	return 0;
}