TYVJ 1744 逆序对数(加强版)
思路:
与a有关的逆序对数=(在a之前出现的比a大的数+在a之后出现的比a小的数)/2
当我们删除a时,减少的是 与a有关的逆序对数,当我们把a的位置填充b时增加的是 与b有关的逆序对数,可以用树状数组求
这样我们相处了nmlogK的算法,显然是不能承受的(K=500000)
但是我们发现当a相同时我们可以将所有的b在logn的时间内算出来,这样复杂度就成了(m+n)logK了
完全可以承受~
PS:不知道为什么我和别人用一样的思路我的代码怎么比他们快3倍啊。。求解释。。(卖萌。。。。)
View Code
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <algorithm> 5 6 #define N 500010 7 8 using namespace std; 9 10 struct P 11 { 12 int a,b,id; 13 }p[N]; 14 15 int c[N],n,m,a[N],fw[N],inc[N]; 16 __int64 ans[N],anssum; 17 18 inline bool cmp(const P &x,const P &y) 19 { 20 return x.a<y.a; 21 } 22 23 inline int lowbit(int x) 24 { 25 return x&-x; 26 } 27 28 inline int getsum(int x) 29 { 30 int rt=0; 31 while(x) 32 { 33 rt+=c[x]; 34 x-=lowbit(x); 35 } 36 return rt; 37 } 38 39 inline void updata(int x,int dt) 40 { 41 while(x<N) 42 { 43 c[x]+=dt; 44 x+=lowbit(x); 45 } 46 } 47 48 void read() 49 { 50 scanf("%d%d",&n,&m); 51 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 52 53 for(int i=1;i<=n;i++) 54 { 55 fw[i]=i-1-getsum(a[i]); 56 updata(a[i],1); 57 } 58 memset(c,0,sizeof c); 59 60 for(int i=n;i>=1;i--) 61 { 62 fw[i]+=getsum(a[i]-1); 63 updata(a[i],1); 64 anssum+=fw[i]; 65 } 66 memset(c,0,sizeof c); 67 68 for(int i=1;i<=m;i++) 69 { 70 scanf("%d%d",&p[i].a,&p[i].b); 71 p[i].id=i; 72 } 73 74 sort(p+1,p+1+m,cmp); 75 } 76 77 void go() 78 { 79 int sp=1; 80 for(int i=1;i<=n;i++) 81 { 82 while(p[sp].a==i) 83 { 84 inc[p[sp].id]=i-1-getsum(p[sp].b); 85 sp++; 86 } 87 updata(a[i],1); 88 } 89 memset(c,0,sizeof c); 90 91 sp=m; 92 for(int i=n;i>=1;i--) 93 { 94 while(p[sp].a==i) 95 { 96 inc[p[sp].id]+=getsum(p[sp].b-1); 97 sp--; 98 } 99 updata(a[i],1); 100 } 101 anssum/=2; 102 for(int i=1;i<=m;i++) 103 ans[p[i].id]=anssum-fw[p[i].a]+inc[p[i].id]; 104 printf("%I64d\n",anssum); 105 for(int i=1;i<=m;i++) 106 printf("%I64d\n",ans[i]); 107 } 108 109 int main() 110 { 111 read(); 112 go(); 113 //system("pause"); 114 return 0; 115 }
没有人能阻止我前进的步伐,除了我自己!