http://www.lydsy.com/JudgeOnline/problem.php?id=4003

可合并堆。

每个点都有一个小根堆,记住可以到这个点的骑士有哪些,以战斗力为关键字。

从底层到顶层不断合并,然后不断取出战斗力的最小值,如果小于防御值,则去掉最小值。

操作可以打标记。

我用了左偏树。

左偏树太不熟悉了,打错了2个地方,去了皮的大土豆~OTATO

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional>
#include<deque>
#include<cctype>
#include<climits>
#include<complex>
//#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj using namespace std; typedef long long LL;
typedef double DB;
typedef complex<DB> CP; #define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define fill(a,l,r,v) fill(a+l,a+r+1,v)
#define re(i,a,b) for(i=(a);i<=(b);i++)
#define red(i,a,b) for(i=(a);i>=(b);i--)
#define ire(i,x) for(typedef(x.begin()) i=x.begin();i!=x.end();i++)
#define fi first
#define se second
#define m_p(a,b) make_pair(a,b)
#define p_b(a) push_back(a)
#define SF scanf
#define PF printf
#define two(k) (1<<(k)) template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-;
inline int sgn(DB x){if(abs(x)<EPS)return ;return(x>)?:-;}
const DB Pi=acos(-1.0); inline int gint()
{
int res=;bool neg=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){neg=;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return (neg)?-res:res;
}
inline LL gll()
{
LL res=;bool neg=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){neg=;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return (neg)?-res:res;
} const int maxN=; int N,M;
vector<int> son[maxN+];
vector<int> Q[maxN+];
int f[maxN+],dep[maxN+],a[maxN+];
LL h[maxN+],v[maxN+];
int c[maxN+];
LL s[maxN+]; struct Tnode
{
Tnode *l,*r;
LL v,mu,add;int id,dis;
inline Tnode(LL _v=,LL _mu=,LL _add=,int _id=,int _dis=){l=;r=;v=_v;mu=_mu;add=_add;id=_id;dis=_dis;}
inline int ldis(){return l?l->dis:;}
inline int rdis(){return r?r->dis:;}
inline void down()
{
if(mu== && add==)return;
if(l)l->v=l->v*mu+add,l->add=mu*l->add+add,l->mu=mu*l->mu;
if(r)r->v=r->v*mu+add,r->add=mu*r->add+add,r->mu=mu*r->mu;
mu=;add=;
}
}; inline Tnode *uni(Tnode *a,Tnode *b)
{
if(!a)return b;
if(!b)return a;
a->down();
b->down();
if(a->v > b->v)swap(a,b);
a->r=uni(a->r,b);
if(a->ldis() < a->rdis())swap(a->l,a->r);
a->dis=a->rdis()+;
return a;
} Tnode mem[maxN+];
Tnode *rt[maxN+]; int ge[maxN+],out[maxN+]; int main()
{
/*freopen("bzoj4003.in","r",stdin);
freopen("bzoj4003.out","w",stdout);*/
int i,j;
N=gint();M=gint();
re(i,,N)h[i]=gll();
re(i,,N)f[i]=gll(),a[i]=gint(),v[i]=gll(),son[f[i]].p_b(i);
re(i,,M)s[i]=gll(),c[i]=gint(),Q[c[i]].p_b(i);
re(i,,N)dep[i]=dep[f[i]]+;
re(i,,M)mem[i]=Tnode(s[i],,,i,);
red(i,N,)
{
re(j,,int(son[i].size())-)
{
int ch=son[i][j];
rt[i]=uni(rt[i],rt[ch]);
}
re(j,,int(Q[i].size())-)
{
int t=Q[i][j];
rt[i]=uni(rt[i],&mem[t]);
}
while(rt[i] && rt[i]->v<h[i])
{
ge[i]++;
int t=rt[i]->id;
out[t]=dep[c[t]]-dep[i];
rt[i]->down();////////////////////////////////////////////注意这里要down
rt[i]=uni(rt[i]->l,rt[i]->r);
}
if(rt[i])
if(a[i]==)
rt[i]->v+=v[i],rt[i]->add+=v[i];
else
rt[i]->v*=v[i],rt[i]->mu*=v[i],rt[i]->add*=v[i];
}
while(rt[])
{
int t=rt[]->id;
out[t]=dep[c[t]];
rt[]->down();////////////////////////////////////////////注意这里要down
rt[]=uni(rt[]->l,rt[]->r);
}
re(i,,N)PF("%d\n",ge[i]);
re(i,,M)PF("%d\n",out[i]);
return ;
}

然后有另外一种不适用这题的方法。

我们发现,如果某个骑士的初始战斗力为x,那么骑士在当前点的战斗力为ax+b,其实a和b只跟出发点和当前点的位置有关,与x无关。

并且我们发现a一定是正数。

类似于LCA,

to[i][j]表示i号点跳2^j次到的点。

jump[i][j]表示,这是一个pair,表示一个初始位置在i号点的骑士的初始战斗力为x,跳2^j次后,战斗力变成jump[i][j].fi*x+jump[i][j].se,其实jump[i][j].fi和jump[i][j].se只和i,有关,与x无关。

minx[i][j]表示,一个初始位置在i号点的骑士的初始战斗力为x,想要跳2^j次,x至少要为minx[i][j]。

容易发现x[i][j]随着j的递增而递增,有单调性。

可以用nlogn的时间求出。

然后对于初始位置在i的骑士,记其初始战斗力为x,二分j,判断x与minx[i][j]的大小关系即可。

但是这道题不适用的地方在于:

(1)MLE

(2)题目保证“任何时候骑士战斗力值的绝对值不超过 10^18”,不是"骑士跑到到根战斗力值的绝对值不超过 10^18“,这样很容易就爆longlong了。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional>
#include<deque>
#include<cctype>
#include<climits>
#include<complex>
//#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj using namespace std; typedef long long LL;
typedef double DB;
typedef pair<LL,LL> PLL;
typedef complex<DB> CP; #define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define fill(a,l,r,v) fill(a+l,a+r+1,v)
#define re(i,a,b) for(i=(a);i<=(b);i++)
#define red(i,a,b) for(i=(a);i>=(b);i--)
#define ire(i,x) for(typedef(x.begin()) i=x.begin();i!=x.end();i++)
#define fi first
#define se second
#define m_p(a,b) make_pair(a,b)
#define SF scanf
#define PF printf
#define two(k) (1<<(k)) template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-;
inline int sgn(DB x){if(abs(x)<EPS)return ;return(x>)?:-;}
const DB Pi=acos(-1.0); inline int gint()
{
int res=;bool neg=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){neg=;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return (neg)?-res:res;
}
inline LL gll()
{
LL res=;bool neg=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){neg=;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return (neg)?-res:res;
} const int maxN=;
const LL INF=(1LL<<)-; int N,M;
LL s[maxN+];int c[maxN+];
int f[maxN+],a[maxN+];
LL h[maxN+],v[maxN+]; int dep[maxN+];
int to[maxN+][];
PLL jump[maxN+][];
LL minx[maxN+][]; int g[maxN+],out[maxN+]; int main()
{
freopen("bzoj4003.in","r",stdin);
freopen("bzoj4003.out","w",stdout);
int i,j;
N=gint();M=gint();
re(i,,N)h[i]=gll();
re(i,,N)f[i]=gint(),a[i]=gint(),v[i]=gll();
re(i,,M)s[i]=gll(),c[i]=gint(); dep[]=;
re(j,,)to[][j]=;
re(j,,)jump[][j]=PLL(,);
re(j,,)minx[][j]=INF;
re(i,,N)
{
dep[i]=dep[f[i]]+;
to[i][]=f[i];
re(j,,)to[i][j]=to[to[i][j-]][j-];
if(a[i]==) jump[i][]=PLL(,v[i]); else jump[i][]=PLL(v[i],);
re(j,,)
{
LL da=jump[i][j-].fi,db=jump[i][j-].se,a=jump[to[i][j-]][j-].fi,b=jump[to[i][j-]][j-].se;
jump[i][j]=PLL(a*da,a*db+b);
}
minx[i][]=h[i];
re(j,,)
{
minx[i][j]=minx[i][j-];
LL a=jump[i][j-].fi,b=jump[i][j-].se,temp=minx[to[i][j-]][j-];
if(temp==INF) upmax(minx[i][j],INF); else upmax(minx[i][j],(temp-b-)/a+);
}
} re(i,,M)
{
int p=c[i];LL x=s[i];
red(j,,)
if(x>=minx[p][j])
{
x=x*jump[p][j].fi+jump[p][j].se;
p=to[p][j];
}
if(x<h[p])g[p]++;
out[i]=dep[c[i]]-dep[p];if(x>=h[p])out[i]++;
} re(i,,N)PF("%d\n",g[i]);
re(i,,M)PF("%d\n",out[i]); return ;
}

bzoj4003的更多相关文章

  1. 左偏树初步 bzoj2809 & bzoj4003

    看着百度文库学习了一个. 总的来说,左偏树这个可并堆满足 堆的性质 和 左偏 性质. bzoj2809: [Apio2012]dispatching 把每个忍者先放到节点上,然后从下往上合并,假设到了 ...

  2. BZOJ4003 [JLOI2015]城池攻占 左偏树 可并堆

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ4003 题意概括 题意有点复杂,直接放原题了. 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑 ...

  3. 【BZOJ4003】[JLOI2015]城池攻占 可并堆

    [BZOJ4003][JLOI2015]城池攻占 Description 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池. 这 n 个城池用 1 到 n 的整数表示.除 1 号 ...

  4. [BZOJ4003][JLOI2015]城池攻占(左偏树)

    这题有多种做法,一种是倍增预处理出每个点往上走2^i步最少需要的初始战斗力,一种是裸的启发式合并带标记splay. 每个点合并能攻占其儿子的所有骑士,删去所有无法攻占这个城市的骑士并记录答案. 注意到 ...

  5. [bzoj4003][JLOI2015]城池攻占_左偏树

    城池攻占 bzoj-4003 JLOI-2015 题目大意:一颗n个节点的有根数,m个有初始战斗力的骑士都站在节点上.每一个节点有一个standard,如果这个骑士的战斗力超过了这个门槛,他就会根据城 ...

  6. BZOJ4003 [JLOI2015]城池攻占

    这题有两种做法来着... 第一种就是一开始想到的比较不靠谱,不过貌似可以过掉: 看从$1$号节点开始到$p$号节点最大需要的体力,记录单调上升的体力,询问的时候二分跳着走就可以了 不过精度问题还有可能 ...

  7. 【BZOJ4003】【JLOI2015】城池攻占(左偏树)

    题面 题目描述 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池.这 n 个城池用 1 到 n 的整数表示.除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖,其中 fi ...

  8. 【BZOJ4003】【JLOI2015】城池攻占

    Description 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池.这 n 个城池用 1 到 n 的整数表示.除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖,其 ...

  9. 左偏树(BZOJ4003)

    左偏树打个标记,没了. #include <cstdio> #include <vector> using namespace std; typedef long long l ...

随机推荐

  1. sicily 4433 DAG?

    题意:输入一个有向图,判断该图是否是有向无环图(Directed Acyclic Graph). 解法:还是深搜 #include<iostream> #include<memory ...

  2. Contest - 2014 SWJTU ACM 手速测试赛(2014.10.31)

    题目列表: 2146 Problem A [手速]阔绰的Dim 2147 Problem B [手速]颓废的Dim 2148 Problem C [手速]我的滑板鞋 2149 Problem D [手 ...

  3. TTTAttributedLabel使用介绍(转)

    TTTAttributedLabel 库地址 https://github.com/TTTAttributedLabel/TTTAttributedLabel 可以实现电话  地址  链接自动查找显示 ...

  4. [置顶] .net技术类面试、笔试题汇总3

    今天本人从成都回到了学校,深刻认识了自己存在很多不足,在这段期间会更加努力,争取早日找到一个好工作! 41.在ASP.NET中有Button控件myButton,要是单击控件时,导航到其他页面http ...

  5. [RxJS] Observables can throw errors

    Whenever we are writing code, we need to remember that things may go wrong. If an error happens in a ...

  6. [Angular 2] Interpolation: check object exists

    In Angular2, sometime we use @Output to pass data to parent component, then parent may pass the data ...

  7. ORA-01810格式代码出现两次 的解决方案

    今早做一个查询页面时,需要查询两个时间区间的跨度,使用TO_DATE函数,一开始写成了Sql代码 TO_DATE('2014-08-04 00:00:00','YYYY-MM-DD HH:mm:ss' ...

  8. oracle获得每周,每月,每季度,每年的第一天

    当前年月日 SELECT trunc(sysdate) , trunc(sysdate,'dd') FROM dual   当年第一天 SELECT trunc(sysdate,'yyyy') FRO ...

  9. 如何改写WebApi部分默认规则

    为什么要改 最近公司在推广SOA框架,第一次正经接触这种技术(之前也有但还是忽略掉吧),感觉挺好,就想自己也折腾一下,实现一个简单的SOA框架 用过mvc进行开发,印象之中WebApi和Mvc好像是一 ...

  10. GDI相关基础知识

    原文链接:http://blog.csdn.net/poem_qianmo/article/details/7333886 GDI(Graphics Device Interface) 图形设备接口, ...