[ CodeVS冲杯之路 ] P2492
不充钱,你怎么AC?
题目:http://codevs.cn/problem/2492/
在此先orz小胖子,教我怎么路径压缩链表,那么这样就可以在任意节点跳进链表啦(手动@LCF)
对于查询操作,直接树状数组(以下简称BIT)维护,修改操作就一个个暴力开方搞,再用差值单点更新BIT
不过这样会TLE,要加一点优化对不对,正如开头所说的路径压缩链表
路径压缩链表其实就是个并查集,在普通的链表里,删去两个连续的节点后会是下面这种情况,如删去2,3
当访问 2 的时候,会跳到3,但 3 已经删除了,这就不合法了
于是我们要用路径压缩,搞成下面这种情况
它是不是非常优秀,就按照并查集一样实现,具体参考代码
那么我们想,为什么要搞链表呢?修改的时候直接暴力扫不就行了?
显然 sqrt(1)=1,那么对于 1 的操作不就是无用功?那么记录下来 1 的位置,然后用链表在扫的时候把它跳转掉,因为区间可以是中间的一段,所以要用路径压缩
记得开long long,然后数组多开 1 个,因为若 r 为极限数据,那么跳到最后一个还会往后面跳一个,没开大的话会RE(反正多开一点好一些),记得链表的 f[n+1]=n+1 也要赋值
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<algorithm> 7 typedef long long LL; 8 using namespace std; 9 10 const int N=100002; 11 LL a[N],s[N]; 12 int f[N],n; 13 namespace QuQ 14 { 15 inline int lowbit(int x) 16 { 17 return x&-x; 18 } 19 inline void plus(int x,LL k) 20 { 21 while (x<=n) 22 { 23 a[x]+=k; 24 x+=lowbit(x); 25 } 26 } 27 inline LL sum(int x) 28 { 29 LL k=0; 30 while (x) 31 { 32 k+=a[x]; 33 x-=lowbit(x); 34 } 35 return k; 36 } 37 } 38 namespace OvO 39 { 40 inline LL read() 41 { 42 char ch=getchar(); 43 LL k=0; 44 while (ch<'0'||ch>'9') ch=getchar(); 45 while (ch>='0'&&ch<='9') 46 { 47 k=k*10+ch-'0'; 48 ch=getchar(); 49 } 50 return k; 51 } 52 inline void write(LL x) 53 { 54 if (x>9) write(x/10); 55 putchar(x%10+'0'); 56 } 57 } 58 inline int find(int x) 59 { 60 return f[x]==x?x:f[x]=find(f[x]); 61 } 62 int main() 63 { 64 int m,i,l,r; 65 LL x; 66 n=OvO::read(); 67 for (i=1;i<=n;i++) 68 { 69 s[i]=OvO::read(); 70 QuQ::plus(i,s[i]); 71 f[i]=i; 72 } 73 f[n+1]=n+1; 74 m=OvO::read(); 75 while (m--) 76 { 77 x=OvO::read(); 78 l=OvO::read(); 79 r=OvO::read(); 80 if (l>r) swap(l,r); 81 if (x) 82 { 83 OvO::write(QuQ::sum(r)-QuQ::sum(l-1)); 84 putchar('\n'); 85 } 86 else for (l=find(l);l<=r;l=find(l+1)) 87 { 88 x=s[l]; 89 x-=s[l]=sqrt(s[l]); 90 if (s[l]==1) f[l]=find(l+1); 91 QuQ::plus(l,-x); 92 } 93 } 94 return 0; 95 }