HDU-4866-Shooting(函数式线段树)
the position of [Li, Ri] , the distance from the starting line is Di(1<=i<=N). Shooting a target can get the bonus points equal to the distance to the starting line. After each shooting targets still exist. Additional, if the previous bonus points is more
than P, then as a reward for the shooting present bonus points doubled(and then check the next one). Player wants to know the bonus points he got in each shot.
The first line has two integers, N, M, X, P(1<=N, M ,X<=100000, P<=1000000000), N represents the total number of target shooting, M represents the number of shooting.
The next N lines of three integers L, R, D (1<=L<=R<=X, 1<=D<=10000000), occupy the position of [L, R] and the distance from the starting line is D.
The next M lines, each line contains four integers x, a, b, c (1<=x<=X, 0<=a,b<=N, 1<=c<=10000000), and K = ( a * Pre + b ) % c. Pre is the bonus point of previous shooting , and for the first shooting Pre=1. It denotes standing in the position x and the player
can shoot the nearest K targets.
4 3 5 8
1 2 6
2 3 3
2 4 7
1 5 2
2 2 1 5
3 1 1 10
4 2 3 7
11
10
18
思路:按到start line的距离建树,把线段转换成两个点,逐一插入,插入的时候同样的节点能够共享(如pre的左子树跟x的左子树同样则直接让x的左子树的指针仅仅想pre的左子树就可以)。详见代码。
#include <cstdio>
#include <algorithm>
#define LL long long
using namespace std; struct P{
int pos,val,flag; bool operator<(const struct P &p) const
{
if(pos==p.pos)
{
if(val==p.val) return flag<p.flag;
else return val<p.val;
}
else return pos<p.pos;
} }pt[4000000],ts;//把每条线段转换成两个点,flag=1代表起点,falg=-1代表终点 int ls[4000000],rs[4000000],T[200005],vv[100000],cnum[4000000],nodenum;//ls指向左子树,rs指向右子树,T[i]为树i的根,cnum记录当前节点插入的值的个数
LL sum[4000000]; void insert(int s,int e,int val,int flag,int pre,int &x)//在pre的基础上插入一个点,假设插左边则右子树与pre的右子树同样,直接让x的右子树指向
{ //pre的右子树,再新建左子树
x=++nodenum; ls[x]=ls[pre];//先让x的左右子树都指向pre的左右子树
rs[x]=rs[pre]; sum[x]=sum[pre]+flag*vv[val];//求和
cnum[x]=cnum[pre]+flag;//记录该节点插入的值的个数 if(s!=e)
{
int mid=(s+e)>>1; if(val<=mid) insert(s,mid,val,flag,ls[pre],ls[x]);//插左边就在pre左子树的基础上建x的左子树
else insert(mid+1,e,val,flag,rs[pre],rs[x]);//右边同理
}
} LL query(int s,int e,int k,int idx)
{
if(s==e) return k*vv[s];//假设到了叶子节点返回k*距离 int mid=(s+e)>>1; if(cnum[ls[idx]]>k) return query(s,mid,k,ls[idx]);//假设插入左子树的值的个数大于k就在左子树找
else if(cnum[ls[idx]]==k) return sum[ls[idx]];//假设插入左子树的值的个数等于k就直接返回左子树的sum
else return sum[ls[idx]]+query(mid+1,e,k-cnum[ls[idx]],rs[idx]);//假设插入左子树的值的个数小于k就在右子树找(k-左子树插入的个数)
} int main()
{
int n,m,x,p,i,l,r,val,cnt,t;
LL pre,pos,a,b,c,k,ans; while(~scanf("%d%d%d%d",&n,&m,&x,&p))
{
for(i=0;i<n;i++)
{
scanf("%d%d%d",&l,&r,&val); vv[i]=val; pt[i*2].pos=l;
pt[i*2].val=val;
pt[i*2].flag=1; pt[i*2+1].pos=r+1;
pt[i*2+1].val=val;
pt[i*2+1].flag=-1;
} sort(vv,vv+n);
cnt=unique(vv,vv+n)-vv;//把距离反复的去掉 int lxd=0;//当前已经建好的树的数量 for(i=0;i<n*2;i++) pt[i].val=lower_bound(vv,vv+cnt,pt[i].val)-vv;//把距离转化成在vv数组里面的下标 sort(pt,pt+n*2);//按(pos,val,flag)升序排序 T[0]=ls[0]=rs[0]=sum[0]=cnum[0]=nodenum=0; pre=1; for(i=0;i<m;i++)
{
scanf("%I64d%I64d%I64d%I64d",&pos,&a,&b,&c); k=(a*pre+b)%c; ts.pos=pos;
ts.val=cnt; t=upper_bound(pt,pt+n*2,ts)-pt;//找到pos相应的第t棵树 while(lxd<t)//假设第t棵树还没建好就建树一直到建好第t棵树为止
{
insert(1,cnt,pt[lxd].val,pt[lxd].flag,T[lxd],T[lxd+1]);//在第lxd棵树的基础上建第lxd+1棵树
lxd++;
} ans=query(1,cnt,k,T[t]);//在第t棵树上查询 if(pre>p) ans*=2; pre=ans; printf("%I64d\n",ans);
}
}
}
HDU-4866-Shooting(函数式线段树)的更多相关文章
- HDU 4866 Shooting(持久化线段树)
view code//第二道持久化线段树,照着别人的代码慢慢敲,还是有点不理解 #include <iostream> #include <cstdio> #include & ...
- HDU 4866 Shooting (主席树)
题目链接 HDU 4866 题意 给定$n$条线段.每条线段平行$x$轴,离x轴的距离为$D$,覆盖的坐标范围为$[L, R]$. 现在有$m$次射击行动,每一次的射击行动可以描述为在横坐标$ ...
- HDU 4866 Shooting 扫描线 + 主席树
题意: 在二维平面的第一象限有\(n(1 \leq n \leq 10^5)\)条平行于\(x\)轴的线段,接下来有\(m\)次射击\(x \, a \, b \, c\). 每次射击会获得一定的分数 ...
- HDU 4866 Shooting(主席树)题解
题意:在一个射击游戏里面,游戏者可以选择地面上[1,X]的一个点射击,并且可以在这个点垂直向上射击最近的K个目标,每个目标有一个价值,价值等于它到地面的距离.游戏中有N个目标,每个目标从L覆盖到R,距 ...
- hdu 5111 树链剖分加函数式线段树
这题说的是给了两棵树,各有100000 个节点,然后Q个操作Q<=50000; 每个操作L1 R1 L2 R2.因为对于每棵树都有一个与本棵树其他点与众不同的值, 最后问 在树上从L1到R1这条 ...
- 学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))
函数式线段树..资瓷 区间第K极值查询 似乎不过似乎划分树的效率更优于它,但是如果主席树套树状数组后,可以处理动态的第K极值.即资瓷插入删除,划分树则不同- 那么原理也比较易懂: 建造一棵线段树(权值 ...
- POJ2104 K-th number 函数式线段树
很久没打代码了,不知道为什么,昨天考岭南文化之前突然开始思考起这个问题来,这个问题据说有很多种方法,划分树什么的,不过对于我现在这种水平还是用熟悉的线段树做比较好.这到题今年8月份的时候曾经做过,那个 ...
- BZOJ 3123 森林(函数式线段树)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3123 题意: 思路:总的来说,查询区间第K小利用函数式线段树的减法操作.对于两棵树的合并 ...
- BZOJ 3207 花神的嘲讽计划Ⅰ(函数式线段树)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3207 题意:给出一个数列,若干询问.每个询问查询[L,R]区间内是否存在某个长度为K的子 ...
- [Usaco2014 Open Gold ]Cow Optics (树状数组+扫描线/函数式线段树)
这道题一上手就知道怎么做了= = 直接求出原光路和从目标点出发的光路,求这些光路的交点就行了 然后用树状数组+扫描线或函数式线段树就能过了= = 大量的离散+模拟+二分什么的特别恶心,考试的时候是想到 ...
随机推荐
- Html页面加回滚
<div class="top-box"> <img src=" class="youlink-img" /><br / ...
- 解决ListView 和ScroolView 共存 listItem.measure(0, 0) 空指针
在网上找到ListView 和ScroolView 共存的方法无非是给他每个listview 重新增加高度,但是android 的设计者始终认为这并不是一种好的实现方法.但是有的时候有必须要用这种蛋疼 ...
- linux杂记(?)命令别名——alias
linux中的命令别名--alias linux中的命令别名--alias 1. 用命令alias可以查询系统中有哪些可用的命令别名 2.添加命令别名 回车查看, 别名建立成功 3.查询命令的地址ty ...
- 对discuz的代码分析学习(二)首页文件
如果当前地址栏存在查询字符,并且是一个数字,条件成立. 查询字符:www.baidu.com/index.php?aaa=bbb aaa=bbb就是查询字符如果条件成立,则把 ...
- python初探-数据类型
数据类型 可以使用BIF type()来查看对象的类型 数字 int float long 布尔(bool) True 机内表示1,机器识别非0 False 机内表示0,机器识别0 空值 None 字 ...
- python parse命令行参数
#!/usr/bin/env python import sys def main(argv): for arg in argv: print arg if __name__ == '__main__ ...
- H3C交换配置PBR最佳实践
简要说明 PBR算是比较常用的功能,需要我们去掌握一下 配置步骤简要 配置BFD 配置track 配置acl 配置policy-based-route 在接口上面应用policy-based-rout ...
- mysql alter table
准备: create table t(x int,y int); 用法 1: 修改列的数据类 alter table t modify column y nvarchar(32); 用法2: 给表加一 ...
- GitHub Android 最火开源项目Top20 GitHub 上的开源项目不胜枚举,越来越多的开源项目正在迁移到GitHub平台上。基于不要重复造轮子的原则,了解当下比较流行的Android与iOS开源项目很是必要。利用这些项目,有时能够让你达到事半功倍的效果。
1. ActionBarSherlock(推荐) ActionBarSherlock应该算得上是GitHub上最火的Android开源项目了,它是一个独立的库,通过一个API和主题,开发者就可以很方便 ...
- 深入了解epoll (转)
一. 介绍 Epoll 是一种高效的管理socket的模型,相对于select和poll来说具有更高的效率和易用性.传统的select以及poll的效率会因为 socket数量的线形递增而导致呈二次乃 ...