【HDU】4866 Shooting 主席树

来源:互联网 发布:视频音轨分离软件 编辑:程序博客网 时间:2024/05/17 21:40

传送门:【HDU】4866 Shooting


题目大意:在一个射击游戏里面,游戏者可以选择地面上【1,X】的一个点射击,并且可以在这个点垂直向上射击最近的K个目标,每个目标有一个价值,价值等于它到地面的距离。游戏中有N个目标,每个目标从L到R,距离地面高度D。每次射击一个目标可以得到目标价值大小的分数,每次射击以后目标不会消失。如果在该点上方的目标个数小于可以射击的次数,那么就当多出来的次数全部射在该点上方最高的目标身上。(举个例子,如果你选择一个点x,可以向上射击a次,该点上方有b个目标,满足a>b,那么你得到的分数就是b个目标的分数之和再加上最上方的目标的分数*(a-b)),并且如果你前一次游戏得到的分数如果大于P,那么这次你得到的分数就翻倍。

现在给你N,M,X,P(1<=N, M ,X<=100000, P<=1000000000),表示有N个目标,M次游戏,坐标的范围【1,X】,分数可以翻倍的阀值。

接下来N行每行L,R,D,表示目标覆盖的范围L到R,高度为D。

接下来M行每行x,a,b,c。表示选择地面上坐标x的点射击。可以射击的次数根据公式K = ( a * Pre + b ) % c得到,其中Pre是上一次游戏得到的分数。


题目分析:

昨天学了主席树,就是为了写掉这题。。。

这题还算简单的吧。。对高度离散化后建立主席树,然后按照1到X的顺序依次插入该坐标上包含的线段的端点,利用标记的思想,左端点L标记+1,右端点R+1的位置-1,表示【L,R】区间内添加了一条线段。主席树同时维护两个信息:该区间的线段个数,该区间的线段分数和。

因为同一个坐标可能有三种情况:没有端点,一个端点,多个端点。

怎么处理呢?如果没有端点,那么直接将第X-1棵树的信息交给X即可。

如果一个端点,照样更新。

如果多个端点,那么第一次在第X-1棵树上更新,然后接下来都在自己的身上更新即可。

查询的时候,访问无需访问历史版本,因为按照插入线段的方式,我们恰好得到在坐标x上方的线段个数,而且还是按照D值从左到右排列的。

本题还有一个需要特别注意的地方就是,同一个坐标的同一高度可能会被多条线段覆盖,需要额外做一些处理。

比如你需要打到这个高度的a个目标,但是这个高度有b个目标,那么可以保证这个节点一定是叶子节点,因为只有一个高度,而高度是唯一的。那么如果a<=b,那么增加的价值就是这个节点的高度*a;如果a>b,那么这个节点一定是最高的那个高度,所以根据题意,增加的价值仍然是高度*a。

所以我们最后查找到叶子节点的时候,如果这个叶子节点是有线段的,那么就用高度*a即可。否则就是0。

那么本题至此已经解决了。

今天看群消息的时候,看到叉姐群里有这么一句话:对于OI党,题目一样A,good idea层出不穷。这就是年轻。大学的ACM反倒模式化了思维。

想想到觉得真的是这样,遇到不会的总是说这个算法我不会,然后再去学这相应的算法,从不自己去天马行空,唉,思维真的可能是模式化了吧?希望有一天我能够有所改变。


代码如下:


#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )#define REV( i , n ) for ( int i = n - 1 ; i >= 0 ; -- i )#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )#define FOV( i , a , b ) for ( int i = a ; i >= b ; -- i )#define REPF( i , a , b ) for ( int i = a ; i < b ; ++ i )#define REPV( i , a , b ) for ( int i = a - 1 ; i >= b ; -- i )#define CLR( a , x ) memset ( a , x , sizeof a )#define mid() ( ( l + r ) >> 1 )typedef long long LL ;const int MAXN = 100005 ;const int MAXE = 200005 ;struct Edge {int h , c , n ;Edge () {}Edge ( int h , int c , int n ) :h ( h ) , c ( c ) , n ( n ) {}} ;struct Seg_Tree {int Ls , Rs ;int c ;LL val ;} ;Edge E[MAXE] ;int H[MAXN] , cntE ;Seg_Tree T[MAXN * 38] ;int idx ;int a[MAXN] , cnt ;int Root[MAXN] ;int N , M , X , P ;LL Pre ;//------------------------------------------------------int unique ( int a[] , int n ) {int cnt = 1 ;sort ( a + 1 , a + n + 1 ) ;FOR ( i , 2 , n )if ( a[i] != a[cnt] )a[++ cnt] = a[i] ;return cnt ;}int lower_bound ( int key ) {int l = 1 , r = cnt + 1 ;while ( l < r ) {int m = mid () ;if ( a[m] >= key )r = m ;elsel = m + 1 ;}return l ;}//------------------------------------------------------int newnode () {return ++ idx ;}void build ( int &o , int l , int r ) {o = newnode () ;T[o].c = 0 ;T[o].val = 0 ;if ( l == r )return ;int m = mid () ;build ( T[o].Ls , l , m ) ;build ( T[o].Rs , m + 1 , r ) ;}int insert ( int old , int pos , int val , int c ) {int root = newnode () ;int now = root ;int l = 1 , r = cnt ;T[now].c = T[old].c + c ;T[now].val = T[old].val + val ;while ( l < r ) {int m = mid () ;if ( pos <= m ) {T[now].Ls = newnode () ;T[now].Rs = T[old].Rs ;now = T[now].Ls ;old = T[old].Ls ;r = m ;}else {T[now].Ls = T[old].Ls ;T[now].Rs = newnode () ;now = T[now].Rs ;old = T[old].Rs ;l = m + 1 ;}T[now].c = T[old].c + c ;T[now].val = T[old].val + val ;}return root ;}LL query ( int now , int kth ) {LL ans = 0 ;int l = 1 , r = cnt ;while ( l < r ) {int m = mid () ;if ( kth <= T[T[now].Ls].c ) {now = T[now].Ls ;r = m ;}else {ans += T[T[now].Ls].val ;kth -= T[T[now].Ls].c ;now = T[now].Rs ;l = m + 1 ;}}if ( T[now].c && kth )ans += T[now].val / T[now].c * kth ;return ans ;}//------------------------------------------------------void init () {cntE = 0 ;CLR ( H , -1 ) ;}void addedge ( int x , int h , int c ) {E[cntE] = Edge ( h , c , H[x] ) ;H[x] = cntE ++ ;}//------------------------------------------------------void solve () {int l , r , h ;init () ;idx = 0 ;cnt = 0 ;Pre = 1 ;FOR ( i , 1 , N ) {scanf ( "%d%d%d" , &l , &r , &h ) ;addedge ( l , h , 1 ) ;addedge ( r + 1 , h , -1 ) ;a[++ cnt] = h ;}cnt = unique ( a , cnt ) ;build ( Root[0] , 1 , cnt ) ;FOR ( x , 1 , X ) {if ( ~H[x] ) {int flag = 0 ;for ( int i = H[x] ; ~i ; i = E[i].n ) {h = E[i].h ;if ( !flag ) {Root[x] = insert ( Root[x - 1] , lower_bound ( h ) , E[i].c * h , E[i].c ) ;flag = 1 ;}elseRoot[x] = insert ( Root[x] , lower_bound ( h ) , E[i].c * h , E[i].c ) ;}}else {Root[x] = newnode () ;T[Root[x]] = T[Root[x - 1]] ;}}int pos , a , b , c ;REP ( i , M ) {scanf ( "%d%d%d%d" , &pos , &a , &b , &c ) ;int kth = ( a * Pre + b ) % c ;LL score = query ( Root[pos] , kth ) ;if ( Pre > P )score <<= 1 ;printf ( "%I64d\n" , score ) ;Pre = score ;}}int main () {while ( ~scanf ( "%d%d%d%d" , &N , &M , &X , &P ) )solve () ;return 0 ;}


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 我娃好动不听话怎么办 初三娃不听话该怎么办 小孩爱动不听话怎么办 宝宝吃饭讨神怎么办 孩子速度太慢怎么办 一年级做作业慢怎么办 小学三年级数学差怎么办 拼音基础太差怎么办 小孩学拼音差怎么办? 孩子字词基础差怎么办 孩子的语文不好怎么办 数学一直学不好怎么办 小孩数学成绩差怎么办 理科生语文不好怎么办 小学阅读题不好怎么办 如果孩子考不好怎么办 6岁不认识数字怎么办 数学一点都不会怎么办 初一数学太差怎么办 三年级孩子数学差怎么办 三年级孩子数学很差怎么办 初中学习不好高中怎么办 四年级孩子数学不好怎么办 孩子学习不开窍怎么办 孩子学习太笨怎么办 老师是个小人怎么办 孩子写字太差怎么办 孩子写字下手重怎么办 孩子一年级数学不好怎么办 孩子数学理解能力差怎么办 智商情商都低怎么办 一年级孩子数学很差怎么办 一年级孩子数学差怎么办 一年级数学学不好怎么办 孩子成绩差该怎么办 小学生数学太差怎么办 小学数学基础差怎么办 孩子一年级学习不好怎么办 快两岁的宝宝老尿裤怎么办 戒母乳宝宝哭闹怎么办 三周岁不肯说话怎么办