博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2018青岛网络赛G - Couleur 区间上的启发式合并
阅读量:5218 次
发布时间:2019-06-14

本文共 4055 字,大约阅读时间需要 13 分钟。

题意:给出\(a[1...n]\),共\(n\)次操作,每次删除一个位置\(p_i\)(强制在线),此时区间会变为两个分离的区间,求每次操作的最大区间逆序对

首先要知道必要的工具,按权值建立的主席树可以在\(O(nlogn)\)内得到任意区间长为\(n\)的逆序对

但每次切除的点如果是不断沿着边来切,那么要统计的区间总长是\(O(n^2)\)

考虑逆序对的贡献是可以互为计算得到的,那么能否每次只对相对较小的区间的复杂度进行统计,得到\(O(nlogn)\)的区间统计总长?

如果已知一个区间\([L,R]\)的总逆序对\(oldans\),切点为\(M\),且更靠左边,

那可以对小区间的逆序数对进行暴力统计,得到\([L,M-1]\)的所有相互贡献,此时记为\(ans1\)
然后再\(O(logn)\)计算\(a[M]\)\([L,M-1]\)的贡献,记为\(tmp\)
最后询问\(T[R]-T[K]\)的子树中比\(a[i],i∈[L,M]\)小的个数,记为\(tmp2\)
那么区间\([L,M-1]\)的逆序数对为\(ans1\),\([M+1,R]\)的逆序数对为\(oldans-ans1-tmp-tmp2\)
以上操作均可以在\(O(nlogn)\)内完成,\(n\)为小区间的长度

切点靠右同理,因此总的复杂度为\(O(nlog^2n)\)

还有一些细节需要处理,如何在一开始就得知\([L,R]\)的总逆序数对,

初始化时先计算出\([1,n]\)的贡献,剩下的必然在前面的操作中已经统计得到\(ans1\)\(ans2\)
考虑区间总是不断分裂的,我们可以用简单的平衡树来维护位置\(M\)对应最近的\(L\)\(R\)
并且答案总是对应于每一个\(L\),都有一个唯一的\(R\)\(ans\)相对应,这部分只需用简单的数组即可得到

\(ans\)的最优解需要在分裂时及时删除对应的元素,再多拿一个multiset动态维护最大值即可

#include
#include
#include
#include
#include
#include
#define rep(i,j,k) for(register int i=j;i<=k;i++)#define rrep(i,j,k) for(register int i=j;i>=k;i--)#define erep(i,u) for(register int i=head[u];~i;i=nxt[i])#define fastIO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)#define println(x) printf("%lld\n",(ll)(x))using namespace std;typedef long long ll;typedef pair
pr;const int MAXN = 1e5+11;const int MAXM = 4e6+11;const int MOD = 142857;const int INF = 1<<30;int T[MAXN];int a[MAXN],p[MAXN];struct FST{ int cnt[MAXM]; int lc[MAXM],rc[MAXM]; int tot; void init(){tot=0;lc[tot]=rc[tot]=cnt[tot]=0;} int build(int l,int r){ int cur=++tot; lc[cur]=rc[cur]=cnt[cur]=0; if(l==r) return cur; int mid=l+r>>1; lc[cur]=build(l,mid); rc[cur]=build(mid+1,r); return cur; } int update(int old,int l,int r,int k,int v){ int cur=++tot; lc[cur]=lc[old]; rc[cur]=rc[old]; cnt[cur]=cnt[old]+v; if(l==r) return cur; int mid=l+r>>1; if(k<=mid) lc[cur]=update(lc[old],l,mid,k,v); else rc[cur]=update(rc[old],mid+1,r,k,v); return cur; } ll query(int cur1,int cur2,int l,int r,int L,int R){//l r if((cur2|cur1)==0) return 0; if(L<=l&&r<=R) return cnt[cur2]-cnt[cur1]; ll ans=0; int mid=l+r>>1; if(L<=mid) ans+=query(lc[cur1],lc[cur2],l,mid,L,R); if(R>mid) ans+=query(rc[cur1],rc[cur2],mid+1,r,L,R); return ans; }}fst;multiset
st;//multiset
inv[MAXN];ll inv[MAXN],invans[MAXN];multiset
ans;int main(){#ifndef ONLINE_JUDGE freopen("stdin.txt","r",stdin);#endif int Test; scanf("%d",&Test); while(Test--){ int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&p[i]); if(n==1){ printf("0\n"); continue; } fst.init(); T[0]=fst.build(1,n); for(int i=1;i<=n;i++){ T[i]=fst.update(T[i-1],1,n,a[i],1); } st.clear(); ans.clear(); st.insert(0),st.insert(n+1); for(int i=0;i<=n+1;i++) inv[i]=0; ll lastans=0; for(int i=1;i<=n;i++){ if(a[i]!=1){ lastans+=fst.query(T[i],T[n],1,n,1,a[i]-1); } } inv[1]=n,invans[1]=lastans; ans.insert(lastans); printf("%lld ",lastans); ll mx=lastans; for(int i=1;i
::iterator it,lo,hi; lo=hi=it=st.find(k); --lo,hi++;//被砍的位置 int l=*lo,r=*hi; l++,--r;//实际操作的位置 ll oldans=invans[l]; ans.erase(ans.find(invans[l]));//这个答案必然无效 if(l==k&&r==k){ ans.insert(0),ans.insert(0); printf("%lld%c",lastans,i==n-1?'\n':' '); continue; } if(l==k){ ll tmp=0; if(a[k]>1) tmp=fst.query(T[k],T[r],1,n,1,a[k]-1); inv[k+1]=r; invans[k+1]=oldans-tmp; ans.insert(0); ans.insert(oldans-tmp); lastans=*--ans.end(); printf("%lld%c",lastans,i==n-1?'\n':' '); continue; } if(r==k){ inv[l]=0; ll tmp=0; if(a[k]
1){ ans1+=fst.query(T[j],T[k-1],1,n,1,a[j]-1); } } ll tmp=0; if(a[k]
::iterator t=inv[l].begin(); ans2=invans[l]; ans2-=(ans1+tmp);//此时包括a[k]的逆序对贡献 for(int j=l;j<=k;j++){ if(a[j]>1){ ans2-=fst.query(T[k],T[r],1,n,1,a[j]-1);//[k+1,r] } } inv[l]=k-1; invans[l]=ans1; inv[k+1]=r; invans[k+1]=ans2; }else{ for(int j=k+1;j<=r;j++){ if(a[j]>1){ ans1+=fst.query(T[j],T[r],1,n,1,a[j]-1);//[k+1,r] } } ll tmp=0; if(a[k]>1) tmp+=fst.query(T[k],T[r],1,n,1,a[k]-1);//[k+1,r]// multiset
::iterator t=inv[l].begin(); ans2=invans[l]; ans2-=(ans1+tmp); for(int j=k;j<=r;j++){ if(a[j]

转载于:https://www.cnblogs.com/caturra/p/9820176.html

你可能感兴趣的文章
hdu 3409 最短路树+树形dp
查看>>
(ios开发学习笔记一)ios项目文件结构
查看>>
Spring中applicationContext.xml的bean里的id和name属性区别
查看>>
MTA---smtp(25,postfix,sendmail),Pop3(110,Devocot), MUA(foxmail) IMAP(server,client rsync)
查看>>
红黑树的删除详解与思路分析——不同于教科书上的算法(dart语言实现)
查看>>
汇编语言1
查看>>
冒泡排序
查看>>
node js学习记录
查看>>
02 EditView控件
查看>>
22 GridView 02
查看>>
如何将添加阿里云备案号并居中显示
查看>>
9 款赏心悦目的 HTML5/CSS3 特效
查看>>
8-cin cout PK scanf printf(速度快慢问题对比)
查看>>
Python学习目录
查看>>
C++ 在继承中虚函数、纯虚函数、普通函数,三者的区别
查看>>
网络三剑客
查看>>
推荐系统
查看>>
IIS7.5配置问题(Win7 Pro,64Bit)
查看>>
centos添加自启动服务的方法
查看>>
vue的mixins的使用
查看>>