题解:BZOJ4399(魔法少女LJJ)
分析: KEY POINTS:平行数据结构的构建(Disjoint_set AND WSegmentTree)
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cmath> 5 using namespace std; 6 #define I int 7 #define D double 8 #define B bool 9 #define C char 10 #define RE register 11 #define V void 12 #define L inline 13 const I MAXN = 4e5 + 10; 14 I m,num,root[MAXN],cnt,auxiliary[MAXN]; 15 struct PRODUCT { I typ,a,b,x,k; }pro[MAXN]; 16 L I read(); 17 struct WSegmentTree{ 18 D product[MAXN * 20]; 19 I seg,sum[MAXN * 20],lc[MAXN * 20],rc[MAXN * 20]; 20 V pushup(I x){ sum[x] = sum[lc[x]] + sum[rc[x]]; product[x] = product[lc[x]] + product[rc[x]]; } 21 V insert(I &x,I l,I r,I pos,I val1,D val2){ 22 if(!x) x = ++seg; 23 if(l == r) { product[x] += val2,sum[x] += val1; return ; } 24 I mid = l + r >> 1; 25 pos <= mid ? insert(lc[x],l,mid,pos,val1,val2) : insert(rc[x],mid + 1,r,pos,val1,val2); 26 pushup(x); 27 } 28 I search(I x,I l,I r,I order){ 29 if(!x || sum[x] < order) return 0; 30 if(l == r) return auxiliary[l]; 31 I mid = l + r >> 1; 32 return order <= sum[lc[x]] ? search(lc[x],l,mid,order) : search(rc[x],mid + 1,r,order - sum[lc[x]]); 33 } 34 I del(I x,I l,I r,I ql,I qr){ 35 I res(0); 36 if(!sum[x]) return 0; 37 if(l == r) { res += sum[x],sum[x] = product[x] = 0; return res; } 38 I mid = l + r >> 1; 39 if(ql <= mid) res += del(lc[x],l,mid,ql,qr); 40 if(qr > mid) res += del(rc[x],mid + 1,r,ql,qr); 41 pushup(x); 42 return res; 43 } 44 I merge(I x,I y,I l,I r){ 45 if(!x || !y) return x + y; 46 if(l == r){ 47 sum[x] += sum[y]; 48 product[x] += product[y]; 49 return x; 50 } 51 I mid = l + r >> 1; 52 lc[x] = merge(lc[x],lc[y],l,mid); 53 rc[x] = merge(rc[x],rc[y],mid + 1,r); 54 pushup(x); 55 return x; 56 } 57 }WSegmentTree; 58 struct Disjoint_set{ 59 I father[MAXN]; 60 I get(I x) { return x == father[x] ? x : father[x] = get(father[x]); } 61 V merge(I x,I y){ 62 I fx = get(x); I fy = get(y); 63 if(fx != fy){ father[fy] = fx; root[fx] = WSegmentTree.merge(root[fx],root[fy],1,cnt); } 64 } 65 }Disjoint_set; 66 signed main(){ 67 m = read(); 68 for(RE I i(1);i <= m; ++ i){ 69 pro[i].typ = read(); 70 if(pro[i].typ == 1) pro[i].x = read(); 71 if(pro[i].typ == 2) pro[i].a = read(),pro[i].b = read(); 72 if(pro[i].typ == 3) pro[i].a = read(),pro[i].x = read(); 73 if(pro[i].typ == 4) pro[i].a = read(),pro[i].x = read(); 74 if(pro[i].typ == 5) pro[i].a = read(),pro[i].k = read(); 75 if(pro[i].typ == 6) pro[i].a = read(),pro[i].b = read(); 76 if(pro[i].typ == 7) pro[i].a = read(); 77 } 78 for(RE I i(1);i <= m; ++ i) 79 if(pro[i].typ == 1 || pro[i].typ == 3 || pro[i].typ == 4) auxiliary[++cnt] = pro[i].x; 80 sort(auxiliary + 1,auxiliary + cnt + 1); 81 cnt = unique(auxiliary + 1,auxiliary + cnt + 1) - auxiliary - 1; 82 for(RE I i(1);i <= m; ++ i) 83 if(pro[i].typ == 1 || pro[i].typ == 3 || pro[i].typ == 4) pro[i].x = lower_bound(auxiliary + 1,auxiliary + cnt + 1,pro[i].x) - auxiliary; 84 for(RE I i(1);i <= m; ++ i){ 85 if(pro[i].typ == 1) Disjoint_set.father[++num] = num,WSegmentTree.insert(root[num],1,cnt,pro[i].x,1,log(auxiliary[pro[i].x])); 86 if(pro[i].typ == 2) Disjoint_set.merge(pro[i].a,pro[i].b); 87 if(pro[i].typ == 3) { I f = Disjoint_set.get(pro[i].a); I tmp = WSegmentTree.del(root[f],1,cnt,1,pro[i].x - 1); 88 if(tmp) WSegmentTree.insert(root[f],1,cnt,pro[i].x,tmp,(D)tmp * log(auxiliary[pro[i].x])); 89 } 90 if(pro[i].typ == 4) { I f = Disjoint_set.get(pro[i].a); I tmp = WSegmentTree.del(root[f],1,cnt,pro[i].x + 1,cnt); 91 if(tmp) WSegmentTree.insert(root[f],1,cnt,pro[i].x,tmp,(D)tmp * log(auxiliary[pro[i].x])); 92 } 93 if(pro[i].typ == 5) { I f = Disjoint_set.get(pro[i].a); 94 printf("%d\n",WSegmentTree.search(root[f],1,cnt,pro[i].k)); 95 } 96 if(pro[i].typ == 6) { I f1 = Disjoint_set.get(pro[i].a); I f2 = Disjoint_set.get(pro[i].b); 97 if(WSegmentTree.product[root[f1]] > WSegmentTree.product[root[f2]]) puts("1"); 98 else puts("0"); 99 } 100 if(pro[i].typ == 7) { I f = Disjoint_set.get(pro[i].a); 101 printf("%d\n",WSegmentTree.sum[root[f]]); 102 } 103 } 104 } 105 L I read(){RE I x(0);RE C z(getchar());while(!isdigit(z))z=getchar();while(isdigit(z))x=(x<<3)+(x<<1)+(z^48),z=getchar();return x;}
问题一:平行数据结构构建(本题主要是Disjoint_set及WSegmentTree)
考虑代码中这两者的关系(同构同算)呈现平行关系,这启发我们尽管完全是不同类型的数据结构,但我们可以主观意义上将多种数据结构合并作为一个大数据结构来解决问题
更通俗的说就是当仅使用一种数据结构的特性难以解决较为复杂的问题时,可以将多种数据结构的特性结合使用解决问题
注意:这种多数据结构合并手段因其客观主体并非一个完整的数据结构,因此我们在对其操作时必须保证其内部各个数据结构进行的是平行操作,这样才不会出现混乱
问题二:数据放缩及注意事项
本题中较难解决的是6比较权值之积,数据范围long long也无法承受,然而考虑关键字“比较”,这启发我们可以类似HASH思想/离散化思想,对数据结构进行放缩(log)解决问题
然而本人在比较是出现了精度问题,原因在于对放缩数据的选择:本人在离散化后将离散化数据再次进行放缩,尽管这样会使数据缩小到一定程度,但是要考虑精度问题(当数据很小,进行log操作
并比较时由于计算机的自动舍位会使比较出错),当然可以写精度函数解决,但是如果直接log原始数据会更方便
问题三:并查集线段树及其应用
并查集在本题中主要应用在确定代表元(根节点)上,也就是说对于这种树状数据结构进行维护时,一定要对根节点进行操作,否则会造成错误
线段树在本题中则是维护了具体数据,这里小总结线段树的基本构成:线段树上每个节点都代表了一个区间(可以实参可以传参),并且记录了对应区间的一定信息,我们在操作时
是通过树上节点的索引找到目标区间位置来进行操作
问题四:语法逻辑优化常数
函数中引用函数时要注意时间上的先后顺序,避免多个函数相互影响的发生
由于函数调用需要一定时间,因此在多次引用时可以类似记忆化,记录函数值进行操作
注:在一定情况下可以将多个函数合并,当然这些函数的返回值不能冲突,也要保证逻辑关系