Bzoj2212:[Poi2011]Tree Rotations:线段树的合并
2016-03-25 09:28
429 查看
题目链接2212:[Poi2011]Tree Rotations
考虑一个节点的左右子树的子树是否交换过对这个节点的逆序对数目没有影响,只有这个节点直接的子树交换才会产生影响
那么我们可以分治的去计算每个节点的贡献,然后向上传递
每个节点的逆序对是左子树的逆序对的数量+右子树的逆序对数量+跨越子树的逆序对数量
我们交换子树更改的就是最后那个跨越子树的逆序对数量,那么:
如果我们交换了左右子树,跨越子树的逆序对数量为没交换时左子树中<mid的数的数量*右子树中>=mid的数的数量
如果我们没有交换左右子树,那么逆序对数量就是左子树中>=mid的数的数量*右子树中<mid的数的数量
然后我们向上传递信息。这一步用线段树合并即可。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=8000010;
LL ans=0,ans1=0,ans2=0;
int n,r[maxn],root,ls[maxn],a[maxn];
int rs[maxn],s[maxn][2],ind=0,t[maxn];
void init_tree(int &x){
x=++ind; scanf("%d",&a[x]);
if (a[x]) return;
init_tree(ls[x]);
init_tree(rs[x]);
}
void push_up(int x){
t[x]=t[s[x][0]]+t[s[x][1]];
}
void insert(int &x,int l,int r,int pos){
if (!x) x=++ind;
if (l==r) {t[x]=1;return;}
int mid=(l+r)>>1;
if (pos<=mid) insert(s[x][0],l,mid,pos);
else insert(s[x][1],mid+1,r,pos);
push_up(x);
}
int merge(int x,int y){
if (!x) return y; if (!y) return x;
ans1+=1LL*t[s[x][1]]*t[s[y][0]];
ans2+=1LL*t[s[x][0]]*t[s[y][1]];
s[x][0]=merge(s[x][0],s[y][0]);
s[x][1]=merge(s[x][1],s[y][1]);
push_up(x); return x;
}
void solve(int x){
if (a[x]) return;
solve(ls[x]); solve(rs[x]);
ans1=ans2=0;
r[x]=merge(r[ls[x]],r[rs[x]]);
ans+=min(ans1,ans2);
}
int main(){
scanf("%d",&n);
init_tree(root);
for (int i=1;i<=ind;++i)
if (a[i]) insert(r[i],1,n,a[i]);
solve(root);
printf("%lld\n",ans);
}
考虑一个节点的左右子树的子树是否交换过对这个节点的逆序对数目没有影响,只有这个节点直接的子树交换才会产生影响
那么我们可以分治的去计算每个节点的贡献,然后向上传递
每个节点的逆序对是左子树的逆序对的数量+右子树的逆序对数量+跨越子树的逆序对数量
我们交换子树更改的就是最后那个跨越子树的逆序对数量,那么:
如果我们交换了左右子树,跨越子树的逆序对数量为没交换时左子树中<mid的数的数量*右子树中>=mid的数的数量
如果我们没有交换左右子树,那么逆序对数量就是左子树中>=mid的数的数量*右子树中<mid的数的数量
然后我们向上传递信息。这一步用线段树合并即可。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=8000010;
LL ans=0,ans1=0,ans2=0;
int n,r[maxn],root,ls[maxn],a[maxn];
int rs[maxn],s[maxn][2],ind=0,t[maxn];
void init_tree(int &x){
x=++ind; scanf("%d",&a[x]);
if (a[x]) return;
init_tree(ls[x]);
init_tree(rs[x]);
}
void push_up(int x){
t[x]=t[s[x][0]]+t[s[x][1]];
}
void insert(int &x,int l,int r,int pos){
if (!x) x=++ind;
if (l==r) {t[x]=1;return;}
int mid=(l+r)>>1;
if (pos<=mid) insert(s[x][0],l,mid,pos);
else insert(s[x][1],mid+1,r,pos);
push_up(x);
}
int merge(int x,int y){
if (!x) return y; if (!y) return x;
ans1+=1LL*t[s[x][1]]*t[s[y][0]];
ans2+=1LL*t[s[x][0]]*t[s[y][1]];
s[x][0]=merge(s[x][0],s[y][0]);
s[x][1]=merge(s[x][1],s[y][1]);
push_up(x); return x;
}
void solve(int x){
if (a[x]) return;
solve(ls[x]); solve(rs[x]);
ans1=ans2=0;
r[x]=merge(r[ls[x]],r[rs[x]]);
ans+=min(ans1,ans2);
}
int main(){
scanf("%d",&n);
init_tree(root);
for (int i=1;i<=ind;++i)
if (a[i]) insert(r[i],1,n,a[i]);
solve(root);
printf("%lld\n",ans);
}
相关文章推荐
- WHOIS类的修改版
- BZOJ3275 Number (最小割)
- Begins and tests
- USACO2013 Nov. Gold T3,一道集合DP
- 数学-素数筛及其拓展
- 最大流模板
- 计算几何模板
- 各种树模板(splay,线段树,可持久化线段树...)
- 上下界网络流初探
- 二分图匹配模板
- CCC 2015 总结&回顾
- 【数论】组合数求模
- 【计算几何】POJ 2318 & POJ 2398
- ACM/ICPC World Finals 2013 A Self-Assembly
- [bzoj1003] [ZJOI2006]物流运输trans
- [bzoj1500][NOI2005]维修数列
- [bzoj1208] [HNOI2004]宠物收养所
- [bzoj1269][AHOI2006]文本编辑器editort
- [bzoj1503][NOI2004]郁闷的出纳员
- bzoj4305 数学