纪中游记(五)
20190807
T0
初
出现了,时限4s的题目!直接暴力。
复
结果爆零。
T1
初
调了两个小时的代码,竟在考试的最后时刻证明为错解,心态大崩。
复
其实这道题只需要用线段树或是树状数组模拟就可以AC,简直是模板题。
在这里只解释一下树状数组的思路(其实线段树也差不多)
先读一遍题,可以发现“阶段”其实就是把 数 移出数组,对其它数的步数产生影响;再思考一下,这不就是树状数组所支持的单点修改么?
如果你没有思路,那么我们跑一遍样例:
首先记录每个数的位置记做wei[i],预处理两个树状数组(加一)
接着在按题目要求依次处理每个阶段的数,把树状数组对应的位置减一
但为什么是两个树状数组呢,实际上处于偶阶段的数会向后移,奇阶段的数会向前移,这时一个树状数组调用起来就非常麻烦,不如再添加一个来维护后缀和,同步修改,分别查询。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int tru[100005],fal[100005]; 4 int n,wei[100005]; 5 void add1(int x,int ui) 6 { 7 while(x<=n) 8 { 9 tru[x]+=ui; 10 x+=x&(-x); 11 } 12 } 13 void add2(int x,int ui) 14 { 15 int op=n-x+1; 16 while(op<=n) 17 { 18 fal[op]+=ui; 19 op+=op&(-op); 20 } 21 } 22 int ask1(int x) 23 { 24 int num=0; 25 while(x) 26 { 27 num+=tru[x]; 28 x-=x&(-x); 29 } 30 return num; 31 } 32 int ask2(int x) 33 { 34 int num=0,op=n-x+1; 35 while(op) 36 { 37 num+=fal[op]; 38 op-=op&(-op); 39 } 40 return num; 41 } 42 inline int read() 43 { 44 int x=0; 45 char ch=getchar(); 46 while(ch<'0'||ch>'9') 47 { 48 ch=getchar(); 49 } 50 while(ch>='0'&&ch<='9') 51 { 52 x=(x<<1)+(x<<3)+ch-'0'; 53 ch=getchar(); 54 } 55 return x; 56 } 57 int main() 58 { 59 scanf("%d",&n); 60 for(int i=1;i<=n;i++) 61 { 62 int op=read(); 63 wei[op]=i; 64 add1(i,1); 65 add2(i,1); 66 } 67 int zu=(n+1)/2; 68 for(int i=1;i<zu;i++) 69 { 70 add1(wei[i],-1);add2(wei[i],-1); 71 printf("%d\n",ask1(wei[i])); 72 add2(wei[n-i+1],-1);add1(wei[n-i+1],-1); 73 printf("%d\n",ask2(wei[n-i+1])); 74 } 75 if(n&1) 76 { 77 printf("0"); 78 } 79 else 80 { 81 add1(wei[zu],-1); 82 printf("%d\n",ask1(wei[zu])); 83 printf("0"); 84 } 85 return 0; 86 }
终
又一道裸树状数组。