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 (树状数组+扫描线/函数式线段树)
这道题一上手就知道怎么做了= = 直接求出原光路和从目标点出发的光路,求这些光路的交点就行了 然后用树状数组+扫描线或函数式线段树就能过了= = 大量的离散+模拟+二分什么的特别恶心,考试的时候是想到 ...
随机推荐
- 获取select赋值
<select class="sel-ul-add" id="xuanzhe"> <option>A</option> &l ...
- Android 内部存储安装apk文件实现
目前国内市场的山寨机横行,安卓手机升级也是一天一个样,对于原来老手机可能没有SDCARD,导致我们的APP不能下载资源,无法更新APP,针对这种情况有以下解决方案.通过以下函数判断是否有SD卡再判断下 ...
- 【转】CentOS 使用yum命令安装出现错误提示”could not retrieve mirrorlist http://mirrorlist.centos.org ***”
源自:http://www.cnblogs.com/yangbingqi/p/3328610.html 刚安装完CentOS,使用yum命令安装一些常用的软件,使用如下命令:yum grouplist ...
- 【LeetCode题意分析&解答】40. Combination Sum II
Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in ...
- Linux例行工作crontab
第一步编辑要定时执行的脚本: myScript.sh myScript.sh的内容为:touch /root/`date +%F' '%T`.txt 为myScript.sh增加可执行权限:chmod ...
- delphi datasnap 心跳包
为了能让我们的服务程序更加稳定,有些细节问题必须解决.就如上一讲中提到的客户端拔掉网线,造成服务器上TCP变成死连接,如果死连接数量过多,对服务器能长期稳定运行是一个巨大的威胁.另外,经过测试,如果服 ...
- js正则验证"汉字"
var nickname = value; var regex = new RegExp("^([\u4E00-\uFA29]|[\uE7C7-\uE7F3]|[a-zA-Z0-9_]){1 ...
- delphi调用外部程序打开文件
delphi调用外部程序打开文件 ShellExecute的各种用法 一.利用系统默认的邮件收发器发送电子邮件 Uses ..., ShellAPI; Var lpHwnd: HWND; lpOper ...
- Android Intent的几种使用方法全面总结
Intent应该算是Android中特有的东西.你能够在Intent中指定程序要运行的动作(比方:view,edit,dial),以及程序运行到该动作时所须要的资料.都指定好后,仅仅要调用startA ...
- 万圣节福利:红孩儿3D引擎开发课程《3ds max导出插件初步》
ds max文件夹,插件文件夹以及3ds max的可执行程序文件夹: 位的,这里要改成x64,否则启动程序后3ds max会提示"不是有效的win32程序"之类的对话框. 然后要将 ...