JZOJ 5989. 【北大2019冬令營模擬2019.1.6】Forest

Description

Description

Input

Input

Output

Output

Sample Input

5 12
10 20 30 40 50
2 3 4 5 2
2 1
2 2
2 3
2 4
2 5
1 4 2
2 1
2 2
2 3
2 4
2 5
3

Sample Output

10
36
28
40
36
9
57
27
28
29
9 57

Data Constraint

Data Constraint
Data Constraint

Solution

  • 我們把 A[i]A[i] 稱作 ii 的“父親”,而所有滿足 A[j]=iA[j]=ijj 稱作 ii 的“兒子”。

  • 觀察到每個點只有 A[i]A[i] 這一個父親,這是一個突破口。

  • 一開始時的 C[i]C[i] 我們是可以直接求出的,現在考慮快速維護 C[i]C[i]

  • 可以發現我們只需要一個不加上父親權值的 C[i]C'[i] 就很好維護了。

  • 於是一個點 iiC[i]=C[i]+B[A[i]]/D[A[i]]C[i]=C'[i]+B[A[i]]/D[A[i]]

  • 那麼修改的時候只需要在幾個點上對 C[i]C'[i]D[i]D[i] 加加減減即可,

  • 這個細節比較多(其實不算多了,下面更……),但很容易就做到 O(1)O(1) 進行操作1、2了。

  • 接下來就是操作3了——回答全局 C[i]C[i] 的最值。

  • 這個很自然會想到用 set 來維護。

  • 具體來說就是,對每個點維護一個存其兒子的 C[i]C[i] 的 set 。

  • 之後全局再維護一個存所有 C[i]C[i] 的 set ,不過這個可以將每個點的 set 中取最大最小值扔進去就夠了。

  • 很“顯然”我們可以在一次修改中 O(log n)O(log\ n) 地修改完所有 set 。。(細節巨多,無法描述。。)

  • 那麼我們直接從全局 set 取出最值就可以回答詢問3了。

  • 總時間複雜度 O(n log n)O(n\ log\ n)

  • 強烈建議在修改 set 的時候打成一個過程(要調用很多次),不然展開打就會像我的代碼一樣與臭又長……

Code

#include<cstdio>
#include<set>
#include<cctype>
using namespace std;
typedef long long LL;
const int N=1e5+5;
int a[N],d[N];
LL b[N],c[N];
multiset<LL>ss[N],val;
multiset<LL>::iterator it;
inline int read()
{
	int X=0,w=0; char ch=0;
	while(!isdigit(ch)) w|=ch=='-',ch=getchar();
	while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
	return w?-X:X;
}
int main()
{
	freopen("forest.in","r",stdin);
	freopen("forest.out","w",stdout);
	int n=read(),q=read();
	for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
	for(int i=1;i<=n;i++)
	{
		a[i]=read();
		d[i]+=2;
		d[a[i]]++;
	}
	for(int i=1;i<=n;i++)
	{
		c[i]+=b[i]%d[i]+b[i]/d[i];
		c[a[i]]+=b[i]/d[i];
	}
	for(int i=1;i<=n;i++) ss[a[i]].insert(c[i]);
	for(int i=1;i<=n;i++)
		if(!ss[i].empty())
		{
			val.insert(*ss[i].begin()+b[i]/d[i]);
			val.insert(*ss[i].rbegin()+b[i]/d[i]);
		}
	while(q--)
	{
		int ty=read();
		if(ty==1)
		{
			int x=read(),y=read(),z=a[x];
			if(y==z) continue;
			if(!ss[z].empty())
			{
				it=val.find(*ss[z].begin()+b[z]/d[z]);
				if(it!=val.end()) val.erase(it);
				it=val.find(*ss[z].rbegin()+b[z]/d[z]);
				if(it!=val.end()) val.erase(it);
			}
			if(!ss[y].empty())
			{
				it=val.find(*ss[y].begin()+b[y]/d[y]);
				if(it!=val.end()) val.erase(it);
				it=val.find(*ss[y].rbegin()+b[y]/d[y]);
				if(it!=val.end()) val.erase(it);
			}
			
			ss[z].erase(ss[z].find(c[x]));
			ss[y].insert(c[x]);
			LL mn=*ss[a[z]].begin(),mx=*ss[a[z]].rbegin();
			ss[a[z]].erase(ss[a[z]].find(c[z]));
			c[z]+=b[z]%(d[z]-1)-b[z]%d[z]-b[x]/d[x]+b[z]/(d[z]-1)-b[z]/d[z];
			ss[a[z]].insert(c[z]);
			LL num=*ss[a[z]].begin();
			if(num^mn)
			{
				it=val.find(mn+b[a[z]]/d[a[z]]);
				if(it!=val.end())
				{
					val.erase(it);
					val.insert(num+b[a[z]]/d[a[z]]);
				}
			}
			num=*ss[a[z]].rbegin();
			if(num^mx)
			{
				it=val.find(mx+b[a[z]]/d[a[z]]);
				if(it!=val.end())
				{
					val.erase(it);
					val.insert(num+b[a[z]]/d[a[z]]);
				}
			}
			mn=*ss[a[a[z]]].begin(),mx=*ss[a[a[z]]].rbegin();
			ss[a[a[z]]].erase(ss[a[a[z]]].find(c[a[z]]));
			c[a[z]]+=b[z]/(d[z]-1)-b[z]/d[z];
			ss[a[a[z]]].insert(c[a[z]]);
			num=*ss[a[a[z]]].begin();
			if(num^mn)
			{
				it=val.find(mn+b[a[a[z]]]/d[a[a[z]]]);
				if(it!=val.end())
				{
					val.erase(it);
					val.insert(num+b[a[a[z]]]/d[a[a[z]]]);
				}
			}
			num=*ss[a[a[z]]].rbegin();
			if(num^mx)
			{
				it=val.find(mx+b[a[a[z]]]/d[a[a[z]]]);
				if(it!=val.end())
				{
					val.erase(it);
					val.insert(num+b[a[a[z]]]/d[a[a[z]]]);
				}
			}
			d[z]--;
			
			a[x]=y;
			mn=*ss[a[y]].begin(),mx=*ss[a[y]].rbegin();
			ss[a[y]].erase(ss[a[y]].find(c[y]));
			c[y]+=b[y]%(d[y]+1)-b[y]%d[y]+b[x]/d[x]+b[y]/(d[y]+1)-b[y]/d[y];
			ss[a[y]].insert(c[y]);
			num=*ss[a[y]].begin();
			if(num^mn)
			{
				it=val.find(mn+b[a[y]]/d[a[y]]);
				if(it!=val.end())
				{
					val.erase(it);
					val.insert(num+b[a[y]]/d[a[y]]);
				}
			}
			num=*ss[a[y]].rbegin();
			if(num^mx)
			{
				it=val.find(mx+b[a[y]]/d[a[y]]);
				if(it!=val.end())
				{
					val.erase(it);
					val.insert(num+b[a[y]]/d[a[y]]);
				}
			}
			mn=*ss[a[a[y]]].begin(),mx=*ss[a[a[y]]].rbegin();
			ss[a[a[y]]].erase(ss[a[a[y]]].find(c[a[y]]));
			c[a[y]]+=b[y]/(d[y]+1)-b[y]/d[y];
			ss[a[a[y]]].insert(c[a[y]]);
			num=*ss[a[a[y]]].begin();
			if(num^mn)
			{
				it=val.find(mn+b[a[a[y]]]/d[a[a[y]]]);
				if(it!=val.end())
				{
					val.erase(it);
					val.insert(num+b[a[a[y]]]/d[a[a[y]]]);
				}
			}
			num=*ss[a[a[y]]].rbegin();
			if(num^mx)
			{
				it=val.find(mx+b[a[a[y]]]/d[a[a[y]]]);
				if(it!=val.end())
				{
					val.erase(it);
					val.insert(num+b[a[a[y]]]/d[a[a[y]]]);
				}
			}
			d[y]++;
			
			if(!ss[z].empty())
			{
				val.insert(*ss[z].begin()+b[z]/d[z]);
				val.insert(*ss[z].rbegin()+b[z]/d[z]);
			}
			if(!ss[y].empty())
			{
				val.insert(*ss[y].begin()+b[y]/d[y]);
				val.insert(*ss[y].rbegin()+b[y]/d[y]);
			}
		}else
		if(ty==2)
		{
			int x=read();
			printf("%lld\n",c[x]+b[a[x]]/d[a[x]]);
		}else
		{
			printf("%lld %lld\n",*val.begin(),*val.rbegin());
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章