其他分享
首页 > 其他分享> > [堆][启发式合并]luogu P3261 [JLOI2015]城池攻占

[堆][启发式合并]luogu P3261 [JLOI2015]城池攻占

作者:互联网

题面

https://www.luogu.com.cn/problem/P3261

分析

考虑对于每个点开堆维护子树中到达这里的所有人的攻击力

对于攻击力改变可以用标记数组给堆打上标记

自下向上合并时,选择较小的堆合并给较大的堆,注意修改每个节点对应的堆编号

当一个值要合并入一个有标记的堆时,直接给这个值除标记值或者减标记值消除标记的影响

记录一下哪些值在哪里被从堆中删除即可

代码

//Tempestissimo 
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;
const int N=3e5+10;
struct Graph {
    int v,nx;
}g[N];
int list[N],cnt,a[N],c[N],dep[N],dth[N],bel[N],ans[N];
ll h[N],v[N],pls[N],multi[N];
int n,m;

ll GCD(ll a,ll b) {return !b?a:GCD(b,a%b);}

struct Num {
    int id;
    ll num,deno;
    
    friend bool operator < (Num a,Num b) {return (long double)a.num/a.deno>(long double)b.num/b.deno;}
    
    friend Num operator * (Num a,ll b) {ll gcd=GCD(a.deno,b);a.deno/=gcd;b/=gcd;a.num*=b;return a;}
    
    friend Num operator / (Num a,ll b) {ll gcd=GCD(a.num,b);a.num/=gcd;b/=gcd;a.deno*=b;return a;}
    
    friend Num operator + (Num a,ll b) {a.num+=b*a.deno;ll gcd=GCD(a.num,a.deno);a.num/=gcd;a.deno/=gcd;return a;}
};
priority_queue<Num> q[N];

void Add(int u,int v) {g[++cnt]=(Graph){v,list[u]};list[u]=cnt;}

void Merge(int &x,int &y) {
    if (q[x].size()<q[y].size()) swap(x,y);
    while (!q[y].empty()) {
        Num temp=q[y].top();q[y].pop();
        temp=(((temp*multi[y])+pls[y])+(-pls[x]))/multi[x];
        q[x].push(temp);
    }
}

void DFS(int u) {
    for (int i=list[u];i;i=g[i].nx) dep[g[i].v]=dep[u]+1,DFS(g[i].v),Merge(bel[u],bel[g[i].v]);
    while (!q[bel[u]].empty()) {
        Num temp=q[bel[u]].top();
        temp=(temp*multi[bel[u]])+pls[bel[u]];
        if ((long double)temp.num/temp.deno>=(long double)h[u]) break;
        ans[dth[temp.id]=u]++;q[bel[u]].pop();
    }
    if (a[u]) multi[bel[u]]*=v[u],pls[bel[u]]*=v[u];
    else pls[bel[u]]+=v[u];
}

int main() {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%lld",&h[i]),bel[i]=i,multi[i]=1;
    for (int i=2,f;i<=n;i++) scanf("%d%d%lld",&f,&a[i],&v[i]),Add(f,i);
    for (int i=1;i<=m;i++) {ll s;scanf("%lld%d",&s,&c[i]);q[c[i]].push((Num){i,s,1});}
    dep[1]=1;DFS(1);
    for (int i=1;i<=n;i++) printf("%d\n",ans[i]);
    for (int i=1;i<=m;i++) printf("%d\n",dep[c[i]]-dep[dth[i]]);
}
View Code

 

标签:P3261,JLOI2015,gcd,int,luogu,ll,num,deno,Num
来源: https://www.cnblogs.com/mastervan/p/14543324.html