1. 程式人生 > >【ZOJ4053】Couleur(主席樹,set,啟發式)

【ZOJ4053】Couleur(主席樹,set,啟發式)

oid bool operator tor std 計算 每次 per return

題意:

有n個位置,每個位置上的數字是a[i],現在有強制在線的若幹個單點刪除操作,每次刪除的位置都不同,要求每次刪除之後求出最大的連續區間逆序對個數

n<=1e5,1<=a[i]<=n

思路:

對於每次刪除操作我們可以考慮被刪除的數字的貢獻

比如區間[l,r]內刪除了x這個位置,被分成了[l,x-1]與[x+1,r]兩個區間

未刪除之前區間總逆序對數可以分為4個部分:[l,x-1]內部,[x+1,r]內部,跨區間,一端為x

一個優秀的結論是內部區間和跨區間部分可以選擇兩端區間內較小的一段進行暴力枚舉計算(啟發式),這樣每個位置均攤被用到了logn次

然後用總的逆序對數減去其他3部分就是較大區間內部的逆序對數

逆序對部分等價於求某個區間內在[l,r]之間數字的個數,顯然使用主席樹進行預處理

現在還要維護區間的插入,刪除與最大值,這個如果只使用一個splay似乎很難維護多個關鍵字

大佬new表示並不需要splay,只需要使用set維護被刪除的點,就能很快找出被刪除的位置處於哪個區間

然而我並不會set,只能照他打一遍了,真是屈辱

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<string>
  4 #include<cmath>
  5 #include<iostream>
  6
#include<algorithm> 7 #include<map> 8 #include<set> 9 #include<queue> 10 #include<vector> 11 using namespace std; 12 typedef long long ll; 13 typedef unsigned int uint; 14 typedef unsigned long long ull; 15 typedef pair<int,int> PII; 16 typedef vector<int
> VI; 17 #define fi first 18 #define se second s 19 #define MP make_pair 20 #define N 110000 21 #define MOD 1000000007 22 #define eps 1e-8 23 #define pi acos(-1) 24 #define oo 1e9 25 26 struct node 27 { 28 int l,r,s; 29 }t[N*45]; 30 31 struct data 32 { 33 ll x; 34 int l,r; 35 }; 36 37 ll Ans[N],f[N],ans; 38 int a[N],root[N],cnt,n; 39 40 set<int>st; 41 typedef set<int>::iterator iter; 42 struct setcmp 43 { 44 bool operator()(const data &x,const data &y) 45 { 46 return x.x>y.x||(x.x==y.x&&x.l<y.l)||(x.x==y.x&&x.l==y.l&&x.r<y.r); 47 } 48 }; 49 set<data,setcmp>S; 50 51 ll query(int l,int r,int x,int y,int L,int R) 52 { 53 if(l>r||x>y) return 0; 54 if(x<=l&&r<=y) return t[R].s-t[L].s; 55 int mid=(l+r)>>1; 56 ll ans=0; 57 if(x<=mid) ans+=query(l,mid,x,y,t[L].l,t[R].l); 58 if(y>mid) ans+=query(mid+1,r,x,y,t[L].r,t[R].r); 59 return ans; 60 } 61 62 void update(int l,int r,int x,int &p) 63 { 64 t[++cnt]=t[p]; 65 p=cnt; 66 t[p].s++; 67 if(l==r) return; 68 int mid=(l+r)>>1; 69 if(x<=mid) update(l,mid,x,t[p].l); 70 else update(mid+1,r,x,t[p].r); 71 } 72 73 int read() 74 { 75 int v=0,f=1; 76 char c=getchar(); 77 while(c<48||57<c) {if(c==-) f=-1; c=getchar();} 78 while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar(); 79 return v*f; 80 } 81 82 int main() 83 { 84 freopen("zoj4053.in","r",stdin); 85 freopen("zoj4053.out","w",stdout); 86 int cas; 87 scanf("%d",&cas); 88 while(cas--) 89 { 90 scanf("%d",&n); 91 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 92 cnt=0; 93 ans=0; 94 st.clear(); 95 st.insert(0); 96 st.insert(n+1); 97 S.clear(); 98 for(int i=1;i<=n;i++) 99 { 100 root[i]=root[i-1]; 101 update(1,n,a[i],root[i]); 102 } 103 ll ans=0; 104 for(int i=1;i<=n;i++) ans+=query(1,n,a[i]+1,n,root[0],root[i-1]); 105 S.insert((data){ans,1,n}); 106 f[1]=ans; 107 for(int i=1;i<=n;i++) 108 { 109 ans=(*S.begin()).x; 110 Ans[i]=ans; 111 ll x; 112 scanf("%lld",&x); 113 x^=ans; 114 iter p=st.lower_bound(x); 115 int r=*p; 116 p--; 117 int l=*p; 118 l++; r--; 119 S.erase(S.lower_bound((data){f[l],l,r})); 120 ans=f[l]; 121 ll t1=0; 122 ll t2=0; 123 if(x-l<r-x) 124 { 125 for(int i=l;i<x;i++) 126 { 127 t1+=query(1,n,1,a[i]-1,root[i],root[x-1]); 128 ans-=query(1,n,1,a[i]-1,root[i],root[r]); 129 } 130 ans-=query(1,n,1,a[x]-1,root[x],root[r]); 131 t2=ans; 132 } 133 else 134 { 135 for(int i=x+1;i<=r;i++) 136 { 137 t2+=query(1,n,a[i]+1,n,root[x],root[i-1]); 138 ans-=query(1,n,a[i]+1,n,root[l-1],root[i-1]); 139 } 140 ans-=query(1,n,a[x]+1,n,root[l-1],root[x-1]); 141 t1=ans; 142 } 143 if(1<=x-1) 144 { 145 S.insert((data){t1,l,x-1}); 146 f[l]=t1; 147 } 148 if(x+1<=r) 149 { 150 S.insert((data){t2,x+1,r}); 151 f[x+1]=t2; 152 } 153 st.insert(x); 154 } 155 for(int i=1;i<n;i++) printf("%lld ",Ans[i]); 156 printf("%lld\n",Ans[n]); 157 158 } 159 return 0; 160 } 161 162 163 164

【ZOJ4053】Couleur(主席樹,set,啟發式)