【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 ;}
- 【HDU】4866 Shooting 主席树
- hdu 4866 Shooting(主席树)
- HDU 4866(Shooting-主席树)
- HDU 4866 Shooting 扫描线+主席树
- HDU 4866 Shooting 题解:主席树
- hdu 4866 Shooting(主席树学习第三弹)
- HDU-4866-Shooting(函数式线段树)
- hdu 4866 Shooting
- HDU 4866Shooting
- hdu 4866 主席树
- hdu 4348 主席树
- HDU 4417 主席树
- HDU 4417 (主席树)
- hdu 5756(主席树)
- hdu 5919 主席树
- HDU 4605 (主席树)
- HDU 4417 主席树
- HDU 5919 主席树
- HDOJ 1166 敌兵布阵
- SQL Server - 事务
- hdu1588
- AsyncTask的使用以及Json解析
- windows 配置adb环境
- 【HDU】4866 Shooting 主席树
- Cocos2d唯一死敌的崛起,OGEngine来了
- SQL语言基础
- 程序编译常提示的错误,及解决办法
- 开篇--基于Android的小巫新闻客户端开发
- JVM
- Java实现的拦截器
- Windows下备份网络文件批处理文件
- 基于Android的小巫新闻客户端开发--UI设计(主界面)