??xml version="1.0" encoding="utf-8" standalone="yes"?>
A的左子结点:2AQ写成A<<1Q?br />A的右子结点:2A+1Q写?A<<1)+1Q?br />q种表示法可以表C出整棵U段树,因ؓQ?br />Q?Q每个结点的子结点的下标都比它大Q这样就不会出现环;
Q?Q每个结点的父结炚w是唯一的(其本w下标整?Q;
但是Q这U表C法有一个弱点:l点的下标是有可能超q?N的,但不会超q?NQ因此,Z表示度ؓN的线D,我们需要开4N的空_然而,其中只有2N-1个位|是有用的(因ؓ表示跨度为N的线D늚U段树共?2N-1)个结点)Q?span style="color: red">q样Q就有一半的I间被浪?/strong>。尤其是q种U段树推q到多维的时?#8212;—Kl线D|只?/2K的位|是有用的,I间利用率非怽。在某些卡空间的场合Q它囧掉了?br />
那么Q有木有好一点的写法呢?最好能使空间利用率辑ֈ100%——也就是所有结点的下标刚好是1~(2N-1)Q!Q?L点一般作?#8220;哨兵”Q不被占用)
q且Q这U写法要保证仅仅q点的下标和它表示的线D늚左右端点Q因为在遍历U段Ӟ下标和左右端点基本上都是同时知道的)Q就能得出其子结点的下标Q而不需要借助额外的东东(最好mid都不需要算Q?br />q种写法是——直接每个结点的DFS遍历ơ序当做它的下标Q!
比如Q跨度ؓ6的线D|Q?br />
Ҏ发现Q根l点下标?Q下标ؓA的结点的左子l点下标?A+1)Q右子结点下标ؓA+SZ(A.L)+1Q其中SZ(A.L)为A的左子树大小?br />若A的左右端点ؓl、rQmid=(l+r)/2Q下取整Q,则A的左子树所表示的线Dؓ[l, mid]Q所以SZ(A.L)=(mid-l+1)*2-1=(mid-l)*2+1=((r-l-1)/2Q上取整Q?*2+1
q样QA的右子结点下标就是A+((r-l+1)/2Q上取整))*2Q也是A加上大于(r-l)的最的偶数Q?br />写在代码里就是:
opr(l, mid, A+1);
opr(mid+1, r, (r-l&1?A+r-l+1:A+r-l+2));
opr(l, mid, A+1);
opr(mid+1, r, A+r-l+2-((r^l)&1));
q样Q我们就成功地将U段树下标的I间利用率提高到?00%Q!以后只需要开2NI间p了囧……
与传l表C法相比Q这U新式表C法虽然可以节省I间Q但旉消耗要更大一些(旉和空间L矛盾的囧……Q,因ؓ它在扑֏子结点的时候需要较多的q算。^均v来,新式表示法比传统表示法要?0~15%Q对于某些坑爹的数据Q对叛_l点调用比较多的那种Q可能慢得更多。此外,在下放标记的时候,传统表示法只需要知道结点下标就行了Q而新式表C法必须同时知道l点的左右端点,q样在dm中就需要传递三个参敎ͼ从而要慢一些,当然Q我们可以不用dmQ直接在操作里面写标C放?img src ="http://www.shnenglu.com/MatoNo1/aggbug/195857.html" width = "1" height = "1" />
]]>
本沙茶去q曾l用双线D|的方法捉了这题(详见q里Q,最q重新审视这题发玎ͼ借助q树,可以得到更简单的Ҏ?br />
题目大意Q?br />有一个长度ؓN的内存条Q每个位|的状态有占用和不占用两种Q有4U操作:
Q?QResetQ清I所有内存(卛_所有位|的状态改Z占用Q删除所有内存块Q;
Q?QNew xQ申请一个新的内存块Q即扑ֈ一个长度ؓx的连l不占用位置区间Q将它们标记为占用,若有多个q样的区_取最左边的,若木有输出Reject NewQ?br />Q?QFree xQ在已申L内存块中Q找到包含位|x的ƈ释放Q将该内存块删除Q同时其占用的所有位|改Z占用Q,若木有内存块包含位置xQ则输出Reject FreeQ?br />Q?QGet xQ找出已甌的内存块中,左vWx个,q输出其左端点;若已甌的内存块数目不x个,则输出Reject Get?br />
可以发现Q每个已l申L内存块尽代表一D区_但仍然是独立的单位,因此Q可以把内存块当成结点,用^衡树l护Q关键字为内存块的左端点位置Q,New操作中内存块的插入与Free操作中内存块的删除均在此q树内q行QReset操作只需要将整棵树销毁即可?br />问题是,在New操作中,需要找C个长度ؓx的连l不占用区间Q而连l的不占用区间ƈ不是独立的单位,因此需要用线D|l护。在U段树中Q需要维?lt;1>l点区间内最长连l不占用块的长度Q?lt;2>l点区间左端、右端连l不占用块的长度Q否则无法维?lt;1>Q;同时Q由于在New操作中需要区间整体改占用QFree操作中又需要区间整体改不占用,所以应当支持整体改值的标记Q对于Reset操作Q只需要全部位|改不占用即可(不能重新建树Q!Q;
q样Q利用一^衡树加一늺D|Q就可以得到一个很单的Ҏ了(代码量是双^衡树或双U段树的一半左叻IQ?br />
q题的启C是Q在解决数据l构l计c题的时候,到底选用什么样的数据结构,是有讲究的,因ؓ它将直接影响到编E复杂度。一般来_U段树比q树好写,但是Ҏ题而言Q双U段树反而不如^衡树加线D|好写Q这是因为对于内存块使用q树维护比使用U段树维护更好。在以后做这U题的时候,要多想一下,扑ֈ便方法?br />
]]>
q是一道线D|操作的极品题Q因为它?个操作刚好覆盖了U段树操作问题的3U处理思\Q可以说是把U段树操作的全部内容都包含进M?br />
U段树是一U静态的数据l构Q因Z늺D|一旦徏成,其Ş态就永远不会发生变化Q改变的仅仅是结点上记录的各U信息的倹{因此,对于U段树操作,核心问题也就是如何维护和处理q些信息。ȝ来说Q对于线D|l点信息的维护和处理Q有以下3U基本思\Q?br />Q?Q左叛_中型Q?br />所谓左叛_中,是用左叛_l点存储的信息来得到父结点存储的信息的|q是最常见的线D|l护Ҏ。D一些简单的例子Q比如结点的SUM域表Cl点区间上所有元素的和,那么q个域维护的Ҏ是“父结点SUM=左子l点SUM+叛_l点SUM”Q再比如l点的MAX/MIN域表Cl点区间上所有元素的最?|那么l护Ҏ是“父结点MAX/MIN=max/min{左子l点MAX/MIN,叛_l点MAX/MIN}”。这U维护方法也比较单,只要在每ơ对子结点进行修改之后upd一下就行了Q对于那些自向下递归Q而且涉及到改值的操作Q在递归完左叛_l点后一定要记得upd一下)Q在q之中有一个很重要的思想是“左右q箋D?#8221;思想Q如果题目中要求L一个区间内的具有某U性质的最长的q箋序列Q也是子区_Q比如最长连l上升子序列?1值问题中q箋?D|者非0D(在具体问题中是q箋的空闲段或者占用段Q等Q可以在每个l点上维护三个域QlS、rS和SQ分别表Cl点区间左端Q从区间的最左端开始的Q具有这U性质的最长连l序列的长度Q该l点区间右端Q到区间的最右端l束的)hq种性质的最长连l序列的长度和该区间内具有这U性质的最长连l序列的长度Q也是要求的那个东东)Q则l护Ҏ?#8220;父结点lS=左子l点lSQ左子结点lS<左子l点lenQ或左子l点len+叛_l点lSQ左子结点lS=左子l点lenQ,父结点rScMQ父l点S=max{左子l点S,叛_l点S,左子l点rS+叛_l点lS}”Q此外,׃要求的这个区间可能被拆成多个q箋的结点区_因此需要按序合ƈq些区间Q合q的Ҏ是:讄S0和S1QS0表示不保证能延下去的区间长度,S0=上一个区间的S1+本区间的lSQS1表示可以延下去的区间长度,S1=上一个区间的S1+本区间lenQ如果本区间整个都是满条g的,即S=lenQ或本区间的rSQ本区间不都是满x件的Q即S<lenQ,取过E中所有S0和区间S的最大值即为结果?br />在HDU2871中,应用左右归中的方法维护的信息是“最长连l空闲段”的长度,New操作需要;
Q?Q调整边界型Q?br />考虑q样一个问题:现在要插入、删除一些[0, 100000)的整敎ͼq且在此q程中不断询问第K的整数是多,怎么办?q树可以实玎ͼ但线D|昄是更好的Ҏ。对每个l点Q存储一个K0DCZ于该l点区间内的整数的个敎ͼ则查扄K的时候只需要不断执行以下操作:Kth(A, K)Q表C在l点A代表的区间内扄K的Q然后,若K<=l点A的左子结点K0|则执行Kth(A的左子结? K)Q否则执行Kth(A的右子结? K-A左子l点的K0)Q这和^衡树似Q,直到扑ֈ叶结点ؓ止。这U方法称?#8220;调整边界?#8221;Q即随着l点深入Q不断羃(自顶向下Q或扩大Q自底向上)范围Q最后找到结果。像扄K这L操作属于自顶向下型,而像“扑ֈX所在的h某种性质的最长的q箋区间”属于自底向上型Q注意和本题的Free不一PQ?br />
Q?Q标记辅助型Q?br />q种l护信息的方法,特点是利用标记来l护信息Q即对于某些l点Q主要是叶结点,因ؓ其标C再下放)Q直接用标记来得到一些数据,比如对于HDU2871q一题,其中对于叶结点位于的插入U段的标P使用的就是标记?br />
下面是本?个操作的具体实现Q?br /><1>U段树结点定义:
本题需要两늺D|Q这是因为New与Free操作对于tot域(插入U段左端点的M敎ͼ会造成不同的媄响,具体来说Q在New操作中,totg会被同时加上Q需要另外一个操作加上)Q然而在Free操作中,totg被同时清I,q样׃D在对某个l点清空Q该l点包含在某个Free操作要清I的U段中)q打?标记之后Q如果紧接着又插入一条包含这个结点区间的新线D,则这个结点的0标记׃丧失Q这样在紧接着下传的时候,其子l点的tot值就不会被清I(事实上已l被清空了)。所以,tot域彻底{Ud另一늺D|里?
int len, mr, lsc, rsc, sc;
} T[MAXN << 2];
struct node0 {
int tot;
bool mr;
} T0[MAXN << 2];
3)FreeQ也涉及两个操作Q分别是找一个点x所在的U段Q插入过的线D)长度以及删除一条线D,对于前者可New插入q的所有线D늚左右端点预存hQ然后找C表区间[x, x]的结点的mr|也就是结点x被编号ؓ马的线D覆盖)Q再在预存的U段中找到即可。对于后者,直接清空卛_Q不要在T0中打标记Q而要单独删除一个totQ;
4)GetQ直接利用T0中的tot扑ֈWK的值即可;
代码
]]>
可以发现本题是求一个比率rateQ得第i个hQ如果用的话Q工资ؓrate*QiQƈ且还要满以下两个限制条Ӟ
Q?Q每人的最低工资限ӞWi个h如果用的话,有rate*Qi>=SiQ即rate>=Si/QiQ?br />Q?Qd销限制Qrate*所有用的h的Qg?lt;=WQ即所有用的h的Qg?lt;=W/rate?br />q样Q可以先所有h按照(S/Q)的值递增排序Q然后枚N要用的最后一个hQ排序后的,也就是S/Q值最大的那个人)Q设为iQ则总花Ҏ省的做法昄是取rate=Si/Qi。然后根据(2Q式得出“所有用的h的Qg?#8221;的最大值W0=W/rateQ其中,Wi个h是必要用的Q故W0值先减去QiQ若W0<QiQ则Wi个h不可使用Q,剩下的问题就变成了在W?~(i-1)个h中(排序后的Q选取一些hQ得他们的Qg和不大于W0Qƈ且选取的h可能多。显然这可以用贪心来实现Q即选取Q值最的若干个h。接下来Q由于题目中N<=500000Q说明需要用数据l构来优化,可是Q的上限只?0000且Q为正整数Q因此,U段树是最好的选择。徏立一表C[1, 20000]的线D|Q每个结点存放两个额外的|sz和sumQ分别表CQg于该l点代表的区间内的h的L以及q些人的Q值d。然后,需要解决上q子问题Ӟ从根l点开始考察l点的sz|不断往下找卛_Q这有点像^衡树的找WK的操作Q?br />L间复杂度QO(N * (log20000 + logN))Q还有排序的旉Q?br />代码
??a title="RQNOJ469" >RQNOJ469
先按照Q意一U属性(q里为AQ递增排序Q然后枚丑րiQ排序后W?位~Wi位的全部lAQ看A属性,它们中A属性最大的一定是iQ,排序后第(i+1)位及以后的,看其B、C两种属性的大小Q若B属性更就看B属性,若C属性更就看C属性,然后得出两种属性的最大值即可。因此可以得C面的法Q先排序Q然后将所有的毛的B或C属性(哪种更小q哪种Q插入^衡树Q这里需要两^衡树Q一存放B属性的|一存放C属性的|Q然后递增枚DiQ注意i=0的情况不要漏掉)Q将Wi位的B或C属性在q树中删除Q然后找Z^衡树中的最大值即可?br />但是需要注意一U特D情况:所有的毛都看同一个属性,此时按照上面的算法可能求不出最优解Q比如:
10 6 5
10 2 8
此时Q第1个C属性更,W?个B属性更,若第1个看C属性,W?个看B属性,则d?+2=7Q而如果两个都看B属性则d?。此时就需要特判(预先求出三种属性中的最大|Q然后再用上面的法求解Q就能保证求出最优解了?br />代码
??a title="PKU2985" >PKU2985
q查?q树基本操作,水题Q不解释?br />代码
?】HNOI2011 括号匚wBracketsQ目前可以看q个帖子Q?br />Splay Treel护序列问题。对于一D|号序列A[1..len]Q定义优先P[0..len]如下Q?br />P[0]=0
P[i]=P[i-1]+1Qi>0且A[i]为左括号Q?br />P[i]=P[i-1]-1Qi>0且A[i]为右括号Q?br />然后QSplay Tree的每个结炚w要记录一个Z值和M|分别表示该结点代表的括号序列中最后一个元素的优先U和优先U最的元素的优先。则可以证明Q这D|号序列调整至q臛_需要改变的括号数目?-M+K+1) / 2Q其中K=Z+((-M+1)/2)*2Q注意这里的/是整除)Q此外由于有swap和invert两个操作Q因此需要记录RM、TM、RTM|分别表示该括号序列执行swap操作后的序列的M倹{执行invert操作后的序列的M|以及同时执行swap和invert操作后序列的M倹{?br />不过Q本题需要严重注意的是:虽然replace操作的标讎ͼ代码中的mk0Q会覆盖掉swapQ代码中的mk1Q和invertQ代码中的mk2Q操作的标记Q但是在下放标记的时候,需要对三种标记逐一判断Qmk0和mk1、mk2q不是不能共存的Q因为有可能先打上mk0标记后再打上mk1或mk2标记?/strong>
本题虽然是静态的Q但仍然不能使用U段树,因ؓU段树无法支持整体翻转(revQ操作?br />代码
]]>
【算法?br />面积qӞ
先将所有矩形的上边界和下边界作为水q线D记录下来,q对所有矩形的左右边界对应的横坐标L化,讄散化后有N个横坐标Q则中间?N-1)Dc对q?N-1)D徏立线D|Q注意,仍然和普通线D|一P是双闭区_不是|上说的一开一闭)Q然后,按照U坐标递增序扫描前面记录的水q线D(设有MD)Q对每一D,如果是上边界Q找到其L化后的范_只需扑ֈ其左右端点离散化后的值l、rQ则对应范围为[l, r-1]Q,q插入线D[l, r-1]Q否则(下边界)Q删除线D[l, r-1]。再然后Q线D|中的每个l点需要记录该区间内的U段覆盖的总长度lenQ若该区间被某条未删除的线D|体覆盖,则len=总长Q否则len=左右子结点len之和Q,每次操作后,累加面积QT[root].len*该水q线D与下一条水q线D늚U坐标之差?br />
周长qӞ
cMQ只不过׃l成周长的线D|水^的也有竖直的Q线D|l点要记录的除了len意外q有一个ssQ表CU段覆盖的端Ҏ量。另外还有lr和rr两个bool|分别表示该线D늚左端点和右端Ҏ否被某条插入的线D覆盖。则T[x].ss = lch(T[x]).ss + rch(T[x]).ss - 2 * (lch(T[x]).rr && rch(T[x].lr))Q若该线D被整体覆盖则T[x].ss=2Q两端点Q。最后,q次得到的T[root].len与上ơ得到的T[root].len之差的绝对值就是水q线D늚长度QT[root].ss*U坐标之差就是竖直线D늚长度?br />