1. 程式人生 > 其它 >P3521 [POI2011]ROT-Tree Rotations - 線段樹合併

P3521 [POI2011]ROT-Tree Rotations - 線段樹合併

題解

考慮對於每個點都開一棵動態開點線段樹,以點權為下標、個數為值,記錄以這個點為根的子樹內的資訊。

可以發現交換某個點 \(u\) 的代價可以快速計算:在把左、右兒子的線段樹合併上來的時候,對於這兩棵線段樹上的對應點 \(p,q\),不交換的代價會增加 \(v_{\mathrm{rson}(p)}\times v_{\mathrm{lson}(q)}\),交換的代價會增加 \(v_{\mathrm{lson}(p)}\times v_{\mathrm{rson}(q)}\)。因為每個點選擇是否交換對其祖先節點並無影響,所以每個點都貪心地選擇代價最小的方案即可。

程式碼
#include <cstdio>
#include <cstring>
#include <cctype>
#include <vector>
using namespace std;
#define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
#define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
template<typename T> void Read(T &x){
	x=0;int _f=1;
	char ch=getchar();
	while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar();
	while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
	x=x*_f;
}
template<typename T,typename... Args> void Read(T &x,Args& ...others){
	Read(x);Read(others...);
}
typedef long long ll;
const int N=6e5+5;
int n,leaf,son[N][2],w[N];
int ReadTree(){
	int x,u=++n;Read(x);
	if(x) w[u]=x;
	else{
		son[u][0]=ReadTree();son[u][1]=ReadTree();
	}
	return u;
}
#define ls(xx) t[xx].ls
#define rs(xx) t[xx].rs
int tot=0;
struct Node{
	int l,r,ls,rs,v;
}t[N*18];
int Newnode(int l,int r){
	t[++tot]=Node{l,r,0,0,0};
	return tot; 
}
void Pushup(int p){t[p].v=t[ls(p)].v+t[rs(p)].v;}
void Add(int p,int pos,int x){
	if(t[p].l==t[p].r){
		t[p].v+=x;return;
	}
	int mid=(t[p].l+t[p].r)>>1;
	if(pos<=mid){
		if(!ls(p)) ls(p)=Newnode(t[p].l,mid);
		Add(ls(p),pos,x);
	}else{
		if(!rs(p)) rs(p)=Newnode(mid+1,t[p].r);
		Add(rs(p),pos,x);
	}
	Pushup(p);
}
int Merge(int u,int v,ll &x,ll &y){
	if(!u||!v) return u^v;
	if(t[u].l==t[u].r){t[u].v+=t[v].v;return u;}
	x+=1LL*t[rs(u)].v*t[ls(v)].v,y+=1LL*t[rs(v)].v*t[ls(u)].v;
	ls(u)=Merge(ls(u),ls(v),x,y),rs(u)=Merge(rs(u),rs(v),x,y);
	Pushup(u);return u;
}
ll Solve(int u,int &rt){
	if(w[u]){
		rt=Newnode(1,leaf);
		Add(rt,w[u],1);return 0;
	}
	int rt1,rt2;ll x=0,y=0,res=0;
	res+=Solve(son[u][0],rt1);res+=Solve(son[u][1],rt2);
	rt=Merge(rt1,rt2,x,y);
	return res+min(x,y);
}
int main(){
	Read(leaf);ReadTree();
	int temp;
	printf("%lld\n",Solve(1,temp));
	return 0;
}