JZOJ 6030. 【GDOI2019模拟2019.2.25】白白的
生活随笔
收集整理的這篇文章主要介紹了
JZOJ 6030. 【GDOI2019模拟2019.2.25】白白的
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Description
Input
Output
Sample Input
4 3
6 0 10 1
1 2
1 0
1 2
Sample Output
1
1
0
Data Constraint
Solution
-
先一遍歸并排序算出初始答案。
-
對于 0 操作,我們需要計算改變的那一位對答案的貢獻。
-
這個就是單點修改+區間查詢比 x 大的數的個數,樹狀數組套權值線段樹即可(動態開點)。
-
對于 1 操作,我們要分裂區間,可以考慮啟發式合并,掃短的那邊算貢獻。
-
但如果用前面的樹套樹來算,這部分復雜度將達到 O(Qlog3n)O(Q\ log^3n)O(Q?log3n) ,不能接受。
-
我們發現由于查詢時查詢的區間(長的那邊)是固定的,這是一個突破口。
-
再開一個一維的權值線段樹來維護就可以了!
-
每次分裂區間時將短的那邊多開成一個線段樹(最多 Q 個)即可。
-
這樣計算復雜度就是 O(Qlog2n)O(Q\ log^2n)O(Q?log2n) 了。
-
總時間復雜度 O((N+Q)log2n)O((N+Q)\ log^2n)O((N+Q)?log2n) ,空間復雜度 O(Nlog2n)O(N\ log^2n)O(N?log2n) 。
Code
#include<cstdio> #include<set> #include<cctype> using namespace std; typedef long long LL; const int N=150005,inf=1e9+1; struct data {int s,l,r; }f[N*30*17]; int n,q,tot,qx,qy,num; LL ans,cnt; int a[N],b[N],c[N]; int rt[N],rt1[N],bel[N]; LL val[N]; set<int>ss; set<int>::iterator it; inline int read() {int X=0,w=0; char ch=0;while(!isdigit(ch)) w|=ch=='-',ch=getchar();while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();return w?-X:X; } void solve(int l,int r) {if(l>=r) return;int mid=l+r>>1;solve(l,mid);solve(mid+1,r);int j=l,k=mid+1,s=l-1;while(j<=mid && k<=r)if(b[k]<b[j]){c[++s]=b[k++];cnt+=mid-j+1;}else c[++s]=b[j++];while(j<=mid) c[++s]=b[j++];while(k<=r) c[++s]=b[k++];for(int i=l;i<=r;i++) b[i]=c[i]; } void change(int &v,int l,int r) {if(!v) v=++tot;f[v].s+=qy;if(l==r) return;int mid=l+r>>1;if(qx<=mid) change(f[v].l,l,mid); else change(f[v].r,mid+1,r); } int find(int v,int l,int r) {if(!v) return 0;if(qx<=l && r<=qy) return f[v].s;int mid=l+r>>1,s=0;if(qx<=mid) s=find(f[v].l,l,mid);if(qy>mid) s+=find(f[v].r,mid+1,r);return s; } inline void add(int x,int y) {qx=y,qy=1;while(x<=n){change(rt[x],0,inf);x+=x&-x;} } inline void del(int x,int y) {qx=y,qy=-1;while(x<=n){change(rt[x],0,inf);x+=x&-x;} } inline LL get(int x,int y,int z) {LL s=0;if(y>z) return 0;qx=y,qy=z;while(x){s+=find(rt[x],0,inf);x-=x&-x;}return s; } int main() {freopen("baibaide.in","r",stdin);freopen("baibaide.out","w",stdout);n=read(),q=read();for(int i=1;i<=n;i++) a[i]=b[i]=read();solve(1,n);ss.insert(0);ss.insert(n+1);for(int i=1;i<=n;i++) add(i,a[i]);val[num=1]=ans=cnt;for(int i=1;i<=n;i++){bel[i]=num;qx=a[i],qy=1;change(rt1[num],0,inf);}for(int j=1;j<=q;j++){int op=read(),x=read();if(j>1) x^=ans;it=ss.upper_bound(x);int r=*it,l=*--it;l++,r--;if(!op){int y=read();if(j>1) y^=ans;ans^=val[bel[l]];LL sum=get(x-1,a[x]+1,inf)-get(l-1,a[x]+1,inf);sum+=get(r,0,a[x]-1)-get(x,0,a[x]-1);val[bel[l]]-=sum;del(x,a[x]);qx=a[x],qy=-1;change(rt1[bel[l]],0,inf);a[x]=y;add(x,y);qx=y,qy=1;change(rt1[bel[l]],0,inf);sum=get(x-1,y+1,inf)-get(l-1,y+1,inf);sum+=get(r,0,y-1)-get(x,0,y-1);val[bel[l]]+=sum;ans^=val[bel[l]];}else{ss.insert(x);if(x-l<r-x){int pos=bel[r];for(int i=l;i<=x;i++){qx=a[i],qy=-1;change(rt1[pos],0,inf);}ans^=val[pos];for(int i=l;i<=x;i++){qx=0,qy=a[i]-1;val[pos]-=find(rt1[pos],0,inf);}if(l<x){num++;for(int i=l;i<x;i++) bel[i]=num;for(int i=l;i<x;i++){qx=a[i],qy=1;change(rt1[num],0,inf);}int len=cnt=0;for(int i=l;i<x;i++) b[++len]=a[i];solve(1,len);val[num]=cnt;ans^=cnt;qx=a[x]+1,qy=inf;cnt+=find(rt1[num],0,inf);val[pos]-=cnt;}ans^=val[pos];}else{int pos=bel[l];for(int i=x;i<=r;i++){qx=a[i],qy=-1;change(rt1[pos],0,inf);}ans^=val[pos];for(int i=x;i<=r;i++){qx=a[i]+1,qy=inf;val[pos]-=find(rt1[pos],0,inf);}if(x<r){num++;for(int i=x+1;i<=r;i++) bel[i]=num;for(int i=x+1;i<=r;i++){qx=a[i],qy=1;change(rt1[num],0,inf);}int len=cnt=0;for(int i=x+1;i<=r;i++) b[++len]=a[i];solve(1,len);val[num]=cnt;ans^=cnt;qx=0,qy=a[x]-1;cnt+=find(rt1[num],0,inf);val[pos]-=cnt;}ans^=val[pos];}}printf("%lld\n",ans);}return 0; }總結
以上是生活随笔為你收集整理的JZOJ 6030. 【GDOI2019模拟2019.2.25】白白的的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 多项式的求逆、取模和多点求值学习小记
- 下一篇: BZOJ 4241: 历史研究