博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷P4069 [SDOI2016]游戏(李超线段树)
阅读量:6452 次
发布时间:2019-06-23

本文共 3409 字,大约阅读时间需要 11 分钟。

题面

题解

如果我们把路径拆成两段,那么这个路径加可以看成是一个一次函数

具体来说,设\(dis_u\)表示节点\(u\)到根节点的距离,那么\((x,lca)\)这条路径上每个节点的权值就会加上\(-dis_ua+dis_xa+b\),而\((lca,y)\)这条路径上每个节点就会加上\(dis_ua+a(dis_x+2\times dis_{lca})+b\)

区间加一次函数并维护最值,就是李超线段树啦~~~~

我们把它给树剖了,那么同一条重链里\(dis\)肯定是递增的,我们就可以把插入直线变成插入线段

顺便注意我们的线段树上的节点是离散化之后的,所以在李超线段树计算的时候要用原来的\(dis\)进行计算

树剖一个\(\log\),李超线段树两个\(\log\),总复杂度是\(O(n\log^3n)\)

我很好奇为啥这个复杂度都能跑过去啊……

//minamoto#include
#define R register#define ll long long#define inf 123456789123456789ll#define fp(i,a,b) for(R int i=(a),I=(b)+1;i
I;--i)#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)template
inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}using namespace std;char buf[1<<21],*p1=buf,*p2=buf;inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}int read(){ R int res,f=1;R char ch; while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1); for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0'); return res*f;}char sr[1<<21],z[20];int C=-1,Z=0;inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}void print(R ll x){ if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x; while(z[++Z]=x%10+48,x/=10); while(sr[++C]=z[Z],--Z);sr[++C]='\n';}const int N=1e5+5;struct eg{int v,nx,w;}e[N<<1];int head[N],tot;inline void add(R int u,R int v,R int w){e[++tot]={v,head[u],w},head[u]=tot;}ll dis[N],bb,kk;int dfn[N],rk[N],top[N],fa[N],sz[N],son[N],dep[N];int n,m,cnt;void dfs1(int u){ dep[u]=dep[fa[u]]+1,sz[u]=1; go(u)if(v!=fa[u]){ fa[v]=u,dis[v]=dis[u]+e[i].w,dfs1(v),sz[u]+=sz[v]; sz[v]>sz[son[u]]?son[u]=v:0; }}void dfs2(int u,int t){ rk[dfn[u]=++cnt]=u,top[u]=t; if(!son[u])return; dfs2(son[u],t); go(u)if(!top[v])dfs2(v,v);}int LCA(R int u,R int v){ while(top[u]!=top[v]){ if(dep[top[u]]
mn),cmin(mn,rc->mn);} inline ll calc(R ll x){return k*x+b;}}pool[N<<2],*rt;int num;inline node *newnode(){return &pool[num++];}int ql,qr;ll res,k,b;void build(node* &p,int l,int r){ p=newnode(),p->b=p->mn=p->lv=p->rv=inf,p->k=0; if(l==r)return; int mid=(l+r)>>1; build(p->lc,l,mid),build(p->rc,mid+1,r);}void update(node *p,int l,int r,ll b,ll k){ if(ql<=l&&qr>=r){ int mid=(l+r)>>1; ll dl=dis[rk[l]],dr=dis[rk[r]],dm=dis[rk[mid]]; if(!p->flag)return p->ins(b,k,dl,dr),void(); ll lv=dl*k+b,rv=dr*k+b; if(lv>=p->lv&&rv>=p->rv)return; if(lv
lv&&rv
rv)return p->ins(b,k,dl,dr),void(); double x=1.0*(b-p->b)/(p->k-k); if(lv<=p->lv){ if(x<=dm)update(p->lc,l,mid,b,k); else bb=p->b,kk=p->k,p->ins(b,k,dl,dr),update(p->rc,mid+1,r,bb,kk); }else{ if(x<=dm)bb=p->b,kk=p->k,p->ins(b,k,dl,dr),update(p->lc,l,mid,bb,kk); else update(p->rc,mid+1,r,b,k); } p->upd(); return; } int mid=(l+r)>>1; if(ql<=mid)update(p->lc,l,mid,b,k); if(qr>mid)update(p->rc,mid+1,r,b,k); p->upd();}void query(node *p,int l,int r){ if(ql<=l&&qr>=r)return cmin(res,p->mn),void(); cmin(res,p->calc(dis[rk[max(l,ql)]])), cmin(res,p->calc(dis[rk[min(r,qr)]])); int mid=(l+r)>>1; if(ql<=mid)query(p->lc,l,mid); if(qr>mid)query(p->rc,mid+1,r);}void change(int u,int v){ while(top[u]!=top[v]){ ql=dfn[top[u]],qr=dfn[u], update(rt,1,n,b,k), u=fa[top[u]]; } ql=dfn[v],qr=dfn[u],update(rt,1,n,b,k);}void ask(int u,int v){ res=inf; while(top[u]!=top[v]){ if(dep[top[u]]

转载于:https://www.cnblogs.com/bztMinamoto/p/10622209.html

你可能感兴趣的文章
hdu 3501 Calculation 2 (欧拉函数)
查看>>
可以免费下载视频素材和模板网站汇总
查看>>
SPOJ104 Highways,跨越数
查看>>
使用rman备份异机恢复数据库
查看>>
Win7-64bit系统下安装mysql的ODBC驱动
查看>>
node中非常重要的process对象,Child Process模块
查看>>
Webserver管理系列:3、Windows Update
查看>>
Linux内核源码详解——命令篇之iostat[zz]
查看>>
Sqlserver2000联系Oracle11G数据库进行实时数据的同步
查看>>
明年计划
查看>>
ORACLE功能GREATEST功能说明具体实例
查看>>
DataGridView 输入数据验证格式(实例)
查看>>
HDOJ 2151
查看>>
Foundation框架 - 快速创建跨平台的网站页面原型
查看>>
open-falcon
查看>>
三菱plc输出指示灯不亮怎么办(转载)
查看>>
doc2vec使用说明(一)gensim工具包TaggedLineDocument
查看>>
intellij maven配置与使用
查看>>
SpringMVC文件下载与JSON格式
查看>>
Q:图像太大,在opencv上显示不完全
查看>>