可并堆
左偏树
bzoj4003 城池攻占
题目大意:一棵树,每个点有一个防御值。m个武士,有攻击力和起始的位置,攻下一个点后会向父亲进攻,攻击力大于等于一个点的防御力就可以攻下,否则死亡。武士攻下每个点后攻击力会变化,加上或者乘上一个数(乘的数保证非负)。问每个城市死亡的武士个数和每个武士攻下的点。
思路:用左偏树维护一个点的武士信息,权值的更改用*a+b的形式更新。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 300005 #define LL long long using namespace std; struct use{int l,r,d;LL ad,ch;}hp[N]; struct uu{int ai;LL vi,hi;}ci[N]; int rt[N]={0},point[N]={0},next[N],cur[N],zh[N],zt,pa[N],ca[N]={0},dis[N]={0}; LL vi[N]; void pushdown(int x){ int l,r;l=hp[x].l;r=hp[x].r; if (l){ vi[l]=vi[l]*hp[x].ch+hp[x].ad; hp[l].ad=hp[l].ad*hp[x].ch+hp[x].ad; hp[l].ch=hp[l].ch*hp[x].ch; }if (r){ vi[r]=vi[r]*hp[x].ch+hp[x].ad; hp[r].ad=hp[r].ad*hp[x].ch+hp[x].ad; hp[r].ch=hp[r].ch*hp[x].ch; }hp[x].ad=0LL;hp[x].ch=1LL; } int merge(int x,int y){ if (!x) return y; if (!y) return x; pushdown(x);pushdown(y); if (vi[x]>vi[y]) swap(x,y); hp[x].r=merge(hp[x].r,y); if (hp[hp[x].l].d<hp[hp[x].r].d) swap(hp[x].l,hp[x].r); if (!hp[x].r) hp[x].d=0; else hp[x].d=hp[hp[x].r].d+1; return x;} void work(int u){ while(rt[u]&&vi[rt[u]]<ci[u].hi){ ++ca[u];pushdown(rt[u]); pa[rt[u]]=dis[pa[rt[u]]]-dis[u]; rt[u]=merge(hp[rt[u]].l,hp[rt[u]].r); }if (u!=1){ if (rt[u]){ if (ci[u].ai==0){ vi[rt[u]]+=ci[u].vi; hp[rt[u]].ad+=ci[u].vi; }else{ vi[rt[u]]*=ci[u].vi; hp[rt[u]].ad*=ci[u].vi; hp[rt[u]].ch*=ci[u].vi; } } }else while(rt[u]){ pushdown(rt[u]); pa[rt[u]]=dis[pa[rt[u]]]-dis[u]+1; rt[u]=merge(hp[rt[u]].l,hp[rt[u]].r); } } int main(){ int n,m,i,fi,u,v; scanf("%d%d",&n,&m); for (i=1;i<=n;++i) scanf("%I64d",&ci[i].hi); for (i=2;i<=n;++i){ scanf("%d%d%I64d",&fi,&ci[i].ai,&ci[i].vi); next[i]=point[fi];cur[fi]=point[fi]=i; }for (i=1;i<=m;++i){ scanf("%I64d%d",&vi[i],&fi); pa[i]=fi; hp[i]=(use){0,0,0,0LL,1LL}; rt[fi]=merge(rt[fi],i); }zh[zt=1]=1;dis[1]=1; while(zt){ u=zh[zt]; if ((v=cur[u])>0){ dis[v]=dis[u]+1; zh[++zt]=v; cur[u]=next[v]; }else{ --zt; for (v=point[u];v;v=next[v]) rt[u]=merge(rt[u],rt[v]); work(u); } }for (i=1;i<=n;++i) printf("%d\n",ca[i]); for (i=1;i<=m;++i) printf("%d\n",pa[i]); }
bzoj4524 伪光滑数
题目大意:x的最大质因子ak,分解后有k项(9=3*3,算两项),ak^k<=N,问第e大的数x是多少。
思路:优先队列保存最大的质因数是x,有y项的最大数(!!)。fi[i][j]表示最大质因数是i,有j项的数的堆,gi[i][j]表示最大质因数至多到i,有j项的数的堆。找次大数的时候可以用可持久化左偏堆维护,因为会不断建点,所以防止mle。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #define N 128 #define up 61 #define len 16000000 #define LL long long using namespace std; struct use{ int x,y;LL v; bool operator<(const use&x)const{return v<x.v;} }; struct hp{int l,r,d;LL v,del;}zh[len]; int fi[N][up]={0},gi[N][up]={0},pr[N],flag[N]={0},zt=0; LL vi[N][up],n; priority_queue<use> que; int getn(int o){ if (!o) return 0; zh[++zt]=zh[o];return zt;} int add(int o,LL x){ if (!o) return o; int ci=getn(o); zh[ci].del*=x;zh[ci].v*=x; return ci;} void pushdown(int o){ if (zh[o].del==1LL) return; zh[o].l=add(zh[o].l,zh[o].del); zh[o].r=add(zh[o].r,zh[o].del); zh[o].del=1LL;} int merge(int a,int b){ if (!a) return b; if (!b) return a; pushdown(a);pushdown(b); if (zh[a].v<zh[b].v) swap(a,b); int c1=getn(a); zh[c1].r=merge(zh[c1].r,b); if ((!zh[c1].l?0:zh[zh[c1].l].d)<(!zh[c1].r?0:zh[zh[c1].r].d)) swap(zh[c1].l,zh[c1].r); if (!zh[c1].r) zh[c1].d=1; else zh[c1].d=zh[zh[c1].r].d+1; return c1;} void del(int &o){ if (!o) return; pushdown(o); o=merge(zh[o].l,zh[o].r);} void pre(int nn){ int i,j,k,ci; for (i=2;i<nn;++i){ if (!flag[i]) pr[++pr[0]]=i; for (j=1;j<=pr[0]&&i*pr[j]<nn;++j){ flag[i*pr[j]]=true; if (i%pr[j]==0) break; } }memset(vi,0,sizeof(vi)); for (i=1;i<=pr[0];++i){ vi[i][0]=1LL; for (vi[i][j=1]=(LL)pr[i];vi[i][j]<=n&&vi[i][j]>vi[i][j-1];){ ++j;vi[i][j]=vi[i][j-1]*(LL)pr[i]; }vi[i][j]=0LL; }gi[0][0]=zt=1; zh[1]=(hp){0,0,0,1LL,1LL}; for (i=1;i<=pr[0];++i){ gi[i][0]=1; for (j=1;vi[i][j];++j){ for (k=1;k<=j;++k) if (gi[i-1][j-k]){ ci=add(gi[i-1][j-k],vi[i][k]); fi[i][j]=merge(fi[i][j],ci); } gi[i][j]=merge(fi[i][j],gi[i-1][j]); que.push((use){i,j,zh[fi[i][j]].v}); } } } int main(){ LL ans;use ci; int k,i,j,mx;scanf("%I64d%d",&n,&k); pre(N); while(k--){ ci=que.top();que.pop(); ans=ci.v; del(fi[ci.x][ci.y]); if (fi[ci.x][ci.y]){ ci.v=zh[fi[ci.x][ci.y]].v; que.push(ci); } }printf("%I64d\n",ans); }
(一开始想的保存所有质因数是第几个,维护一个递增序列,用treap维护,但复杂度过不去)