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 (树状数组+扫描线/函数式线段树)
这道题一上手就知道怎么做了= = 直接求出原光路和从目标点出发的光路,求这些光路的交点就行了 然后用树状数组+扫描线或函数式线段树就能过了= = 大量的离散+模拟+二分什么的特别恶心,考试的时候是想到 ...
随机推荐
- IIS上不能播放mp4
iis不支持mp4格式,需要手动添加. 进入iis服务管理器,打开你的网站,然后点击MIME类型---添加(扩展名:mp4 MIME类型:application/octet-stream) 如此即 ...
- [转]WIN7系统安装Apache 提示msvcr110.DLL
我的系统是WIN7 64位,安装配置Apache2.4.7(httpd-2.4.7-win64-VC11.zip )提示如下错误 VC++2012 2013 百度网盘地址:http://pan.bai ...
- 使用PHP把下划线分隔命名的字符串 转换成驼峰式命名方式 , 把下划线后面的第一个字母变成大写
最近项目使用symfony框架,这个框架对数据库的操作在这个团队里使用的是ORM进行操作,说实话使用ORM的开发效率和运行效率不一定高多少,到是它的实体命名和现有数据库字段的命名不太一样,ORM实体属 ...
- codeforces 632C. The Smallest String Concatenation 排序
题目链接 给出n个字符串, 将他们连在一起, 求连玩之后字典序最小的那种情况. 按a+b<b+a排序.... #include <iostream> #include <vec ...
- c# winform读取xml创建菜单
动态创建菜单使得程序灵活性大大增加,本文根据读取xml文件中的配置菜单项来动态创建菜单,代码如下: using System; using System.Collections.Generic; us ...
- c++程序内存泄露检測工具
功能: 用于检測c++程序的内存泄露. 原理: 事实上非常easy,就是通过函数的重载机制,捕获应用程序的new, new[] , delete , delete[], malloc,calloc,f ...
- linux内核之网络协议栈
https://www.ibm.com/developerworks/cn/linux/l-ntflt/
- 有关VS2008制作安装包时遇到的问题详解
公司最近要做一个安装包,然而在做的时候遇到好多问题,这里我一一记录下来 一.先用VS2008建一个Setup项目,添加你需要打包的文件,这里我就不具体介绍了,网上一搜都好多,这时我们一般都需要在安装前 ...
- 与html相关的知识点整理
梳理html时发现的一些问题.总结一下,答案大都从网上找来. 一.html 与 htm 的区别 没有本质的区别..htm是在win32时代,系统只能识别3位扩展名时使用的.现在一般都使用.html. ...
- 2015年最棒的10个 JavaScript 框架
JavaScript是最流行的前端开发程序设计语言.它为WEB开发者提供了能够设计出具有丰富功能.干净用户界面的WEB应用的能力.JavaScript框架使得WEB应用的设计变的简单,并且它能够提供很 ...