Codeforces 785E 题解(树套树-树状数组套线段树)
来源:互联网 发布:流畅的python pdf 编辑:程序博客网 时间:2024/06/06 08:47
题目大意:
对于一个长度为n的序列进行k次操作,每次操作都是交换序列中的某两个数。对于每一个操作,回答当前序列中有多少个逆序对。
题解:
每次更改序列都可以理解为,将答案减去被调换的位置原有数字的对答案的贡献,然后调换两数字的位置,然后将答案加上被调换的位置在调换之后的数字对答案的贡献。
每一个数字对答案的贡献都可以理解为在其出现位置之前的比它大的数字的个数加上在其出现位置之后的比它小的数字的个数。
由此,用树状数组套线段树可做。树状数组是根据位置维护的,树状数组的每个结点包含一个权值线段树,但是直接开权值线段树的话空间会爆,所以线段数要动态开点,那么每一次修改只会至多使用log2n的空间。
同时也要注意,计算贡献的时候要注意被调换的两个数字之间的相互影响。
代码:
树套树版本
#include <cstdio>#include <iostream>using namespace std;#define lowbit(k) (k&-(k))const int maxn=int(2e5)+111;int n,m;struct Node { int sum,ls,rs; Node() {} Node(int s,int l,int r):sum(s),ls(l),rs(r) {}}node[maxn*200];int root[maxn],tot=0;void seg_modify(int k,int l,int r,int pos,int val) { if(l==r && l==pos) { node[k].sum=val; return; } int mid=(l+r)>>1; int &ls=node[k].ls,&rs=node[k].rs; if(pos<=mid) { if(!ls) ls=++tot; seg_modify(ls,l,mid,pos,val); } else { if(!rs) rs=++tot; seg_modify(rs,mid+1,r,pos,val); } node[k].sum=(ls?node[ls].sum:0)+(rs?node[rs].sum:0); return;}int seg_query(int k,int l,int r,int ql,int qr) { if(ql<=l && r<=qr) return node[k].sum; int mid=(l+r)>>1; int &ls=node[k].ls,&rs=node[k].rs; if(qr<=mid) return ls?seg_query(ls,l,mid,ql,qr):0; if(ql> mid) return rs?seg_query(rs,mid+1,r,ql,qr):0; return (ls?seg_query(ls,l,mid,ql,qr):0)+(rs?seg_query(rs,mid+1,r,ql,qr):0);}void bit_build() { for(int i=1;i<=n;i++) root[i]=i; tot=n; for(int i=1;i<=n;i++) { int len=lowbit(i); for(int j=i;j>=(i-len+1);j--) seg_modify(root[i],1,n,j,1); } return;}int bit_query(int pos,int l,int r) { int res=0; while(pos) { res+=seg_query(root[pos],1,n,l,r); pos-=lowbit(pos); } return res;}void bit_modify(int pos,int val,int dir) { while(pos<=n) { seg_modify(root[pos],1,n,val,dir); pos+=lowbit(pos); } return;}int a[maxn];int main() {#ifndef ONLINE_JUDGE freopen("input.txt","r",stdin); freopen("output.txt","w",stdout);#endif // ONLINE_JUDGE scanf("%d%d",&n,&m); bit_build(); long long ans=0; for(int i=1;i<=n;i++) a[i]=i; while(m--) { int x,y; scanf("%d%d",&x,&y); int g1=bit_query(n,1,a[x]-1)-bit_query(x,1,a[x]-1)+bit_query(x-1,a[x]+1,n); bit_modify(x,a[x],0); int g2=bit_query(n,1,a[y]-1)-bit_query(y,1,a[y]-1)+bit_query(y-1,a[y]+1,n); bit_modify(y,a[y],0); ans-=g1+g2; swap(a[x],a[y]); bit_modify(x,a[x],1); int c1=bit_query(n,1,a[x]-1)-bit_query(x,1,a[x]-1)+bit_query(x-1,a[x]+1,n); bit_modify(y,a[y],1); int c2=bit_query(n,1,a[y]-1)-bit_query(y,1,a[y]-1)+bit_query(y-1,a[y]+1,n); ans+=c1+c2; printf("%I64d\n",ans); } return 0;}
分块套树状数组版本(lewin)
#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>using namespace std;// taken from here: https://github.com/igrsk/spoj/blob/master/SWAPS.cpp#define FORO(i,n) for(int i = 0;i < n;i++)#define FORI(i,n) for(int i = 1;i <= n;i++) const int MAXN = 200000;const int MAXA = 200000;const int MAXSQRTN = 500;int A[MAXN];int N, M;int bit[MAXSQRTN+1][MAXA+1];int sqrtN;void bitinc(int i,int v,int *d) { for(;i <= MAXA;i += i&-i) d[i]+=v;}void bitins(int x,int y,int v) { while(x <= sqrtN) { bitinc(y,v,bit[x]); x += x&-x; }}int bitsum(int x,int y) { int ret = 0; for(;x > 0;x-=x&-x) for(int yy = y;yy > 0;yy-=yy&-yy) ret += bit[x][yy]; return ret;}void init() { for(sqrtN = 1;sqrtN*sqrtN < N;sqrtN++) ; for(int i = 0;i < N;i++) { bitins(i/sqrtN+1,A[i],1); }}int query(int i,int x) { int ret = bitsum(i/sqrtN,x); // 0 ~ sqrtN-1, sqrtN ~ 2*sqrtN-1, ... for(int j = sqrtN*(i/sqrtN);j <= i;j++) if(A[j] <= x) ret++; return ret;}int main() { freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); scanf("%d %d",&N, &M); FORO(i,N) A[i] = i+1; init(); long long orans = 0; FORO(i,N) { orans += i-query(i,A[i])+1; } cout<<"orans:"<<orans<<endl; int X, Y, q1, q2; FORO(mm,M) { scanf("%d %d",&X,&Y); // update and query X--; Y--; if (X != Y) { q1 = A[X]; q2 = A[Y]; orans -= (X-query(X-1,A[X])-1)+(query(N-1,A[X]-1)-query(X,A[X]-1)); bitins(X/sqrtN+1,A[X],-1); A[X] = q2; bitins(X/sqrtN+1,q2,1); orans += (X-query(X-1,q2)-1)+(query(N-1,q2-1)-query(X,q2-1)); orans -= (Y-query(Y-1,A[Y])-1)+(query(N-1,A[Y]-1)-query(Y,A[Y]-1)); bitins(Y/sqrtN+1,A[Y],-1); A[Y] = q1; bitins(Y/sqrtN+1,q1,1); orans += (Y-query(Y-1,q1)-1)+(query(N-1,q1-1)-query(Y,q1-1)); } printf("%lld\n",orans); } return 0;}
分块套vector版本(kmjp)
#include <bits/stdc++.h>using namespace std;typedef signed long long ll;#undef _P#define _P(...) (void)printf(__VA_ARGS__)#define FOR(x,to) for(x=0;x<(to);x++)#define FORR(x,arr) for(auto& x:arr)#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)#define ALL(a) (a.begin()),(a.end())#define ZERO(a) memset(a,0,sizeof(a))#define MINUS(a) memset(a,0xff,sizeof(a))//-------------------------------------------------------int N,Q;int A[201010];int L,R;const int D=500;vector<int> V[500];void erase(int id,int v) { int b=id/D; int i; FOR(i,V[b].size()) if(V[b][i]==v) { V[b].erase(V[b].begin()+i); return; }}void add(int id,int v) { int b=id/D; int i; FOR(i,V[b].size()) if(v<V[b][i]) { V[b].insert(V[b].begin()+i,v); return; } V[b].push_back(v);}int getmore(int id,int v) { int i,j; int ret=0; FOR(i,500) { if(id<(i+1)*D) { for(j=i*D;j<id;j++) if(A[j]>v && A[j]!=1<<20) ret++; break; } else { ret += V[i].end()-lower_bound(ALL(V[i]),v); } } return ret;}int getless(int id,int v) { int i,j; int ret=0; FOR(i,500) { if(id<(i+1)*D) { for(j=i*D;j<id;j++) if(A[j]<v) ret++; break; } else { ret += lower_bound(ALL(V[i]),v)-V[i].begin(); } } return ret;}void solve() { int i,j,k,l,r,x,y; string s; cin>>N>>Q; FOR(i,N) { A[i]=i+1; add(i,A[i]); } ll ret=0; while(Q--) { cin>>L>>R; L--,R--; if(L==R) { cout<<ret<<endl; continue; } if(L>R) swap(L,R); if(A[L]<A[R]) ret--; else ret++; ret-=getmore(R,A[R]); ret-=A[R]-1-getless(R,A[R]); ret-=getmore(L,A[L]); ret-=A[L]-1-getless(L,A[L]); erase(R,A[R]); erase(L,A[L]); swap(A[L],A[R]); add(R,A[R]); add(L,A[L]); ret+=getmore(R,A[R]); ret+=A[R]-1-getless(R,A[R]); ret+=getmore(L,A[L]); ret+=A[L]-1-getless(L,A[L]); cout<<ret<<endl; }}int main(int argc,char** argv){ string s;int i; if(argc==1) ios::sync_with_stdio(false), cin.tie(0); FOR(i,argc-1) s+=argv[i+1],s+='\n'; FOR(i,s.size()) ungetc(s[s.size()-1-i],stdin); solve(); return 0;}
1 0
- Codeforces 785E 题解(树套树-树状数组套线段树)
- codeforces 785E (树状数组套平衡树)
- Codeforces Round #431 (Div. 2) E. Goodbye Souvenir CDQ分治 或 离散化 线段树套树状数组
- bzoj3110(线段树套线段树、树状数组套线段树)
- zoj 2112 (主席树,树状数组套线段树)
- zoj 2112 (主席树,树状数组套线段树)
- uva11990 - ``Dynamic'' Inversion(线段树套树状数组+分块)
- 【ZJOI2013】K 大数查询 ( 树状数组套线段树 )
- [BZOJ2674]Attack(整体二分+树状数组套线段树)
- [BZOJ2674]Attack(整体二分+树状数组套线段树)
- 【树状数组套线段树】数列
- 【bzoj 1901】树状数组套线段树
- uva11990 线段树套树状数组
- codeforces 628E Zbazi in Zeydabad(线段树||树状数组优化)
- Codeforces Round #407 (Div. 1) E. New task(线段树+树状数组)
- Codeforces Round #424 (Div. 2, )-树状数组|线段树-E. Cards Sorting
- [树套树] 可持久化线段树 树状数组套值域线段树
- 【DP】【线段树】【树状数组】saber 题解
- 如何学习C语言?学C语言有什么秘诀?
- 为控件添加动画的方法(Alpha透明度,rotate旋转,scale缩放,translate位移)
- Trie——51nod1526 分配笔名
- 有关三角形坐标面积代码
- STM32F407(5)
- Codeforces 785E 题解(树套树-树状数组套线段树)
- 170316 汇编-Debug指令、寄存器和内存
- Unity手游框架 之 界面管理(一)
- gcc编译之常见错误
- Unity5.5 制作2D游戏
- L1-025. 正整数A+B
- Python爬虫抓取马蜂窝游记的照片 基于xpath
- 535. Encode and Decode TinyURL
- 低鲁棒车流分析