题目链接:
洛谷 P3521 [POI2011]ROT-Tree Rotations
loj 「POI2011 R2 Day2」旋转树木 Tree Rotations(数据加强过)
都是同一个题。
题解
讲真这题不看题解,我还不太会写出来,涉及树的合并操作,有点不太会。
PS:这篇博客放在草稿箱好久,主要是之后我还要补树的合并的相关知识,当时对那个merge函数了解不是很清晰
1、左右子树的交换不影响节点,只要两种情况取最小即可。
2、确定左右子树是否交换后,又和子树合并的操作。
3、add函数还是权值线段树的模板,merge函数是树合并的操作
4、这里的输入有点特别,可以用dfs来读取这些叶子节点。
void dfs(int &i){
x=read();
int ls,rs;
if(!x){
dfs(ls=0); dfs(rs=0);
a=b=0; i=ls;
merge(i,rs);
ans+=min(a,b);
}
else add(i,1,n);
}
ac的部分代码
#define mid ((l+r)>>1)
const int maxn=4e6+5;
int n,rt,cnt,x;
int sum[maxn],t[maxn][2];
ll a,b,ans;
void add(int &i,int l,int r){
i=++cnt; sum[i]++;
if(l==r) return;
if(x<=mid) add(t[i][0],l,mid);
else add(t[i][1],mid+1,r);
}
void merge(int &i,int j){
if(!i||!j){
i=i|j;
return;
}
sum[i]+=sum[j];
a+=(ll)sum[t[i][0]]*sum[t[j][1]];
b+=(ll)sum[t[i][1]]*sum[t[j][0]];
merge(t[i][0],t[j][0]);
merge(t[i][1],t[j][1]);
}
void dfs(int &i){
x=read();
int ls,rs;
if(!x){
dfs(ls=0); dfs(rs=0);
a=b=0; i=ls;
merge(i,rs);
ans+=min(a,b);
}
else add(i,1,n);
}
int main(){
n=read();
dfs(rt);
printf("%lld",ans);
}