JLOI2015 真的不愧是NOI出题组出的,题目难度够吊。不过每一道都是结论题和乱搞题真的很不好玩。。。
首先贴下popoqqq的blog吧
感性的认识就是感觉到部分分是个斐波那契数列的通项公式然后考虑是否能把该式子化成递推式然后矩阵乘法算了。。感觉是超级恶心的一道题了,还得用快速乘法。。。
首先这道题我们先考虑暴力,也就是每个点向父亲跑,我们考虑能否一起做,可以发现在同一个点的骑士可以用一个堆维护一起跳(因为没有改变优先级的操作)然后再用懒标记维护,我们可以直接用一个可合并堆来维护就可以啦
当然这道题用线段树,倍增都是可行的,就是空间比较拙计罢了,需要用一些奇奇怪怪的方法来干
CODE:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long ll; 7 struct node{ 8 node *l,*r;int id,dis;ll s,lx,ly; 9 node(ll _s,int _id){ 10 l=r=0; 11 s=_s,id=_id,lx=1,ly=0;dis=1; 12 } 13 }; 14 inline void update(node* x) { 15 if (x->l) { 16 x->l->s*=x->lx; 17 x->l->s+=x->ly; 18 x->l->lx*=x->lx; 19 x->l->ly*=x->lx; 20 x->l->ly+=x->ly; 21 } 22 if (x->r) { 23 x->r->s*=x->lx; 24 x->r->s+=x->ly; 25 x->r->lx*=x->lx; 26 x->r->ly*=x->lx; 27 x->r->ly+=x->ly; 28 } 29 x->lx=1;x->ly=0; 30 } 31 node* merge(node* x,node *y) { 32 if (!x) return y; 33 if (!y) return x; 34 update(x);update(y); 35 if (x->s>y->s) swap(x,y); 36 x->r=merge(x->r,y); 37 if (!x->l||x->l->dis<x->r->dis) swap(x->l,x->r); 38 x->dis=x->r?x->r->dis+1:0; 39 return x; 40 } 41 inline node* del(node *x) { 42 update(x); 43 return merge(x->l,x->r); 44 } 45 #define maxn 300010 46 int dep[maxn],fa[maxn],a[maxn],ans[maxn],sum[maxn]; 47 ll h[maxn],v[maxn]; 48 node *root[maxn]; 49 int main(){ 50 freopen("fall.in","r",stdin); 51 freopen("fall.out","w",stdout); 52 int n,m; 53 scanf("%d%d",&n,&m); 54 for (int i=1;i<=n;i++) scanf("%lld",h+i); 55 dep[1]=1; 56 for (int i=2;i<=n;i++) { 57 scanf("%d%d%lld",fa+i,a+i,v+i); 58 dep[i]=dep[fa[i]]+1; 59 } 60 for (int i=1;i<=m;i++) { 61 ll s;int c; 62 scanf("%lld%d",&s,&c); 63 root[c]=merge(root[c],new node(s,i)); 64 ans[i]=dep[c]; 65 } 66 for (int i=n;i;i--) { 67 while (root[i]&&root[i]->s<h[i]) { 68 sum[i]++; 69 ans[root[i]->id]-=dep[i]; 70 root[i]=del(root[i]); 71 } 72 if (!root[i]) continue; 73 if (a[i]==0) { 74 root[i]->s+=v[i]; 75 root[i]->ly+=v[i]; 76 } 77 else { 78 root[i]->s*=v[i]; 79 root[i]->lx*=v[i]; 80 root[i]->ly*=v[i]; 81 } 82 root[fa[i]]=merge(root[fa[i]],root[i]); 83 } 84 for (int i=1;i<=n;i++) printf("%d\n",sum[i]); 85 for (int i=1;i<=m;i++) printf("%d\n",ans[i]); 86 return 0; 87 }