1. 程式人生 > 實用技巧 >Codeforces 643D. Bearish Fanpages 題解

Codeforces 643D. Bearish Fanpages 題解

題目連結:D. Bearish Fanpages

題目大意:洛谷


題解:做這一道題的主要任務,讀題,讀題,讀題……(我能說我題目讀了將近 1h 嗎

因為是基環樹,所以考慮在樹上怎麼做,大概就是維護每一個節點的孩子對它的貢獻,然後父親單獨拎出來處理一下就行了。

放到基環樹上呢?

維護後繼是它的節點,然後把它的後繼單獨拎出來處理一下,然後,因為出題人保證了點不會重複,所以直接拿 set 維護就可以了。

程式碼有點長,細節有點多(比起某毒瘤出的資料結構題來說好多了)。

下面是程式碼:

#include <set>
#include <cstdio>
using namespace std;
template<typename Elem>
void read(Elem &a){
	a=0;
	char c=getchar();
	while(c<'0'||c>'9'){
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		a=(a<<1)+(a<<3)+(c^48);
		c=getchar();
	}
}
typedef long long ll;
const int Maxn=100000;
int n,q;
int deg[Maxn+5],f[Maxn+5];
bool vis[Maxn+5];
ll a[Maxn+5],t[Maxn+5];
multiset<ll> s[Maxn+5];
void del(int x){
	if(vis[x]&&!s[x].empty()){
		vis[x]=0;
		s[0].erase(s[0].find((*s[x].begin())+t[x]/(deg[x]+1)));
		s[0].erase(s[0].find((*(--s[x].end()))+t[x]/(deg[x]+1)));
	}
}
void add(int x){
	if(!vis[x]&&!s[x].empty()){
		vis[x]=1;
		s[0].insert((*s[x].begin())+t[x]/(deg[x]+1));
		s[0].insert((*(--s[x].end()))+t[x]/(deg[x]+1));
	}
}
void work(int i,int j){
	del(f[i]);
	del(f[f[i]]);
	del(f[f[f[i]]]);
	del(j);
	del(f[j]);
	del(f[f[j]]);
	s[f[i]].erase(s[f[i]].find(a[i]));
	s[f[f[i]]].erase(s[f[f[i]]].find(a[f[i]]));
	a[f[i]]-=t[i]/(deg[i]+1);
	a[f[i]]-=t[f[i]]-deg[f[i]]*(t[f[i]]/(deg[f[i]]+1));
	a[f[i]]+=t[f[i]]-(deg[f[i]]-1)*(t[f[i]]/deg[f[i]]);
	s[f[f[i]]].insert(a[f[i]]);
	s[f[f[f[i]]]].erase(s[f[f[f[i]]]].find(a[f[f[i]]]));
	a[f[f[i]]]-=t[f[i]]/(deg[f[i]]+1);
	a[f[f[i]]]+=t[f[i]]/deg[f[i]];
	s[f[f[f[i]]]].insert(a[f[f[i]]]);
	deg[f[i]]--;
	deg[j]++;
	s[j].insert(a[i]);
	s[f[j]].erase(s[f[j]].find(a[j]));
	a[j]+=t[i]/(deg[i]+1);
	a[j]-=t[j]-(deg[j]-1)*(t[j]/deg[j]);
	a[j]+=t[j]-deg[j]*(t[j]/(deg[j]+1));
	s[f[j]].insert(a[j]);
	s[f[f[j]]].erase(s[f[f[j]]].find(a[f[j]]));
	a[f[j]]-=t[j]/deg[j];
	a[f[j]]+=t[j]/(deg[j]+1);
	s[f[f[j]]].insert(a[f[j]]);
	add(f[i]);
	add(f[f[i]]);
	add(f[f[f[i]]]);
	add(j);
	add(f[j]);
	add(f[f[j]]);
	f[i]=j;
}
int main(){
	read(n),read(q);
	for(int i=1;i<=n;i++){
		read(t[i]);
	}
	for(int i=1;i<=n;i++){
		read(f[i]);
	}
	for(int i=1;i<=n;i++){
		deg[i]++;
		deg[f[i]]++;
	}
	for(int i=1;i<=n;i++){
		a[i]+=t[i]-deg[i]*(t[i]/(deg[i]+1));
		a[f[i]]+=t[i]/(deg[i]+1);
	}
	for(int i=1;i<=n;i++){
		s[f[i]].insert(a[i]);
	}
	for(int i=1;i<=n;i++){
		add(i);
	}
	for(int i=1;i<=q;i++){
		int op;
		read(op);
		if(op==1){
			int x,y;
			read(x),read(y);
			work(x,y);
		}
		else if(op==2){
			int x;
			read(x);
			printf("%d\n",a[x]+t[f[x]]/(deg[f[x]]+1));
		}
		else{
			printf("%d %d\n",(*s[0].begin()),(*(--s[0].end())));
		}
	}
	return 0;
}