P3521 [POI2011]ROT-Tree Rotations
线段树合并怎么那么水。。。我以为是比较高深的东西。。。。。
对每个子树维护一棵动态开点的值域线段树,资磁线段树合并
合并子树的顺序对于上面没有影响,所以每一层合并都要取最小值
然后根据线段树的优秀性质,只要在merge的时候每个节点都算一下跨过mid的逆序对数(类似分治的思想),计入两种情况的ans
用两个ans的min更新总的Ans
#include<bits/stdc++.h>
#define il inline
#define vd void
#define rg register
typedef long long ll;
il char gc(){
static char buf[233333],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,233333,stdin),p1==p2)?EOF:*p1++;
}
il int gi(){// fread读入优化
char ch=gc();int sum=0;
while(!(ch>='0'&&ch<='9'))ch=gc();
while(ch>='0'&&ch<='9')sum=sum*10+(ch^48),ch=gc();
return sum;
}
int n;
ll ans=0,sum1=0,sum2=0;
int ls[10000019],rs[10000019],sum[10000019],id;
il int newnode(rg int x){
rg int ret=++id,y=ret,l=1,r=n;
sum[ret]=1;
while(l!=r){
rg int md=(l+r)>>1;
if(x<=md)ls[y]=++id,y=ls[y],sum[y]=1,r=md;
else rs[y]=++id,y=rs[y],sum[y]=1,l=md+1;
}
return ret;
}
il int merge(rg int x,rg int y){
if(x==0||y==0)return x|y;
sum1+=1ll*sum[ls[x]]*sum[rs[y]];
sum2+=1ll*sum[rs[x]]*sum[ls[y]];
sum[x]+=sum[y];
ls[x]=merge(ls[x],ls[y]);
rs[x]=merge(rs[x],rs[y]);
return x;
}
il int solve(){
rg int x=gi();
if(x)return newnode(x);
else{
int l=solve(),r=solve();
sum1=sum2=0;
int ret=merge(l,r);
ans+=std::min(sum1,sum2);
return ret;
}
}
int main(){
n=gi();
solve();
printf("%lld\n",ans);
return 0;
}
吐槽:
loj上数据好多了。。。
博主是蒟蒻,有问题请指出,谢谢!
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。