zoukankan      html  css  js  c++  java
  • P4069 [SDOI2016]游戏 树剖+李超树

    题意:

    戳这里

    分析:

    首先树上路径操作,要用树剖

    其次,操作等价于区间加一条线段,然后查询区间最小值

    但是与普通李超树不同,这次 (x) 值并不连续,每次插入的线段下标是和给定起点的距离,那么我们更改一下维护的信息,线段树上 (a) 点的 $x $ 值是它离根的距离,然后我们将操作转化,每次插入的线段分成两条

    1. (s o lca)

    这一部分距离随编号减小而增大,所以斜率由 (k) 变为 (-k)(b) 的初值就是 (dis[s]*k+b)

    1. (lca o t)

    这一部分距离随编号增大而增大,,那么斜率不变, (b) 值变为 ((dis[s]-(dis[lca]*2)*k+b))

    之后就是维护区间最小值,但注意由于标记永久化的操作,我们需要每一次将答案和对应区间内 (max(l,ql)) ~ (min(r,qr)) 的部分的最小值取 (min)

    代码:

    #include<bits/stdc++.h>
    #define lc (rt<<1)
    #define rc (rt<<1)|1
    using namespace std;
    
    namespace zzc
    {
    	long long read()
    	{
    		long long x=0,f=1;char ch=getchar();
    		while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    		while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    		return x*f;
    	}
    	
    	const int maxn = 1e5+5;
    	long long n,m,cnt,idx;
    	long long head[maxn],siz[maxn],fa[maxn],son[maxn],top[maxn],dep[maxn],dfn[maxn],dis[maxn],id[maxn];
    	
    	struct edge
    	{
    		int to,nxt,val;
    	}e[maxn<<1];
    	
    	void add(int u,int v,int w)
    	{
    		e[++cnt].to=v;
    		e[cnt].nxt=head[u];
    		e[cnt].val=w;
    		head[u]=cnt;
    	}
    	
    	struct line
    	{
    		long long k,b;
    	    line (long long k=0,long long b=0):k(k),b(b){}
    		long long calc(long long pos)
    		{
    			return k*pos+b;
    		}
    	};
    	
    	struct node
    	{
    		line L;
    		long long val;
    		bool flag;
    		node(line L,long long val,bool flag=false):L(L),val(val),flag(flag){}
    		node(){}
    	}t[maxn<<2];
    	
    	void dfs1(int u,int ff)
    	{
    		dep[u]=dep[ff]+1;fa[u]=ff;siz[u]=1;son[u]=0;
    		for(int i=head[u];i;i=e[i].nxt)
    		{
    			int v=e[i].to;
    			if(v==ff) continue;
    			dis[v]=dis[u]+e[i].val;
    			dfs1(v,u);
    			siz[u]+=siz[v];
    			if(siz[v]>siz[son[u]]) son[u]=v;
    		}
    	}
    	
    	void dfs2(int u,int bel)
    	{
    		top[u]=bel;dfn[u]=++idx;id[idx]=u;
    		if(son[u]) dfs2(son[u],bel);
    		for(int i=head[u];i;i=e[i].nxt)
    		{
    			int v=e[i].to;
    			if(v==fa[u]||v==son[u]) continue;
    			dfs2(v,v);
    		}
    	}
    	
    	void pushup(int rt)
    	{
    		t[rt].val=min(t[rt].val,min(t[lc].val,t[rc].val));
    	}
    	
    	void build(int rt,int l,int r)
    	{
    		t[rt]=node(line(0,123456789123456789ll),123456789123456789ll,true);
    		if(l==r) return ;
    		int mid=(l+r)>>1;
    		build(lc,l,mid);build(rc,mid+1,r);
    		pushup(rt);
    	}
    	
    	int lca(int x,int y)
    	{
    		while(top[x]!=top[y])
    		{
    			if(dep[top[x]]<dep[top[y]]) swap(x,y);
    			x=fa[top[x]];
    		}
    		return dep[x]>dep[y]?y:x;
    	}
    	
    	void update(int rt,int l,int r,int ql,int qr,line x)
    	{
    		if(ql<=l&&r<=qr)
    		{
    			long long ll=dis[id[l]];
    			long long rr=dis[id[r]];
    			long long mid=(l+r)>>1,mmid=dis[id[mid]];
    			long long lp=x.calc(ll),rp=x.calc(rr);
    			long long lq=t[rt].L.calc(ll),rq=t[rt].L.calc(rr);
    			if(!t[rt].flag) t[rt].flag=true,t[rt].L=x;
    			else if(lp<lq&&rp<rq) t[rt].L=x;
    			else if(lp<lq||rp<rq)
    			{
    				if(x.calc(mmid)<t[rt].L.calc(mmid)) swap(x,t[rt].L);
    				if(x.calc(ll)<t[rt].L.calc(ll)) update(lc,l,mid,ql,qr,x);
    				else update(rc,mid+1,r,ql,qr,x);
    			}
    			t[rt].val=min(t[rt].val,min(t[rt].L.calc(ll),t[rt].L.calc(rr)));
    			if(l!=r) pushup(rt);
    			return ;
    		}
    		int mid=(l+r)>>1;
    		if(ql<=mid) update(lc,l,mid,ql,qr,x);
    		if(qr>mid) update(rc,mid+1,r,ql,qr,x);
    		if(l!=r) pushup(rt);
    	}
    	
    	long long query(int rt,int l,int r,int ql,int qr)
    	{
    		if(ql<=l&&r<=qr) return t[rt].val;
    		int mid=(l+r)>>1;
    		long long res=123456789123456789ll;
    		if(t[rt].flag) res=min(res,min(t[rt].L.calc(dis[id[max(l,ql)]]),t[rt].L.calc(dis[id[min(r,qr)]])));
    		if(ql<=mid) res=min(res,query(lc,l,mid,ql,qr));
    		if(qr>mid) res=min(res,query(rc,mid+1,r,ql,qr));
    		return res;
    	}
    	
    	void update_tree(int u,int v,long long k,long long b)
    	{
    		line x=line(k,b);
    		while(top[u]!=top[v])
    		{
    			update(1,1,n,dfn[top[u]],dfn[u],x);
    			u=fa[top[u]];
    		}
    		update(1,1,n,dfn[v],dfn[u],x);
    	}
    	
    	long long query_tree(int s,int t)
    	{
    		long long res=123456789123456789;
    		while(top[s]!=top[t])
    		{
    			if(dep[top[s]]<dep[top[t]]) swap(s,t);
    			res=min(res,query(1,1,n,dfn[top[s]],dfn[s]));
    			s=fa[top[s]];
    		}
    		if(dep[s]>dep[t]) swap(s,t);
    		res=min(res,query(1,1,n,dfn[s],dfn[t]));
    		return res;
    	}
    	
    	void work()
    	{
    		long long opt,s,t,a,b,c;
    		n=read();m=read();
    		for(int i=1;i<n;i++)
    		{
    			a=read();b=read();c=read();
    			add(a,b,c);add(b,a,c);
    		}
    		dfs1(1,0);dfs2(1,1);
    		build(1,1,n);
    		for(int i=1;i<=m;i++)
    		{
    			opt=read();s=read();t=read();
    			if(opt==1)
    			{
    				a=read();b=read();
    				int tmp=lca(s,t);
    				update_tree(s,tmp,-a,dis[s]*a+b);
    				update_tree(t,tmp,a,(dis[s]-(dis[tmp]<<1))*a+b);
    			}
    			else
    			{
    				printf("%lld
    ",query_tree(s,t));
    			}
    		}
    	}
    	
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
    } 
    
  • 相关阅读:
    HttpResponse对象、JsonResponse、StreamingHttpResponse、FileResponse
    for循环
    字符串功能
    (二)第一个Spring Boot工程
    (一)安装Docker和Kubernetes
    如何解决CHM打开乱码的问题
    [译]PyUnit—Python单元测试框架(1)
    正则表达式
    Java开发心得
    Shell获取文件后缀名
  • 原文地址:https://www.cnblogs.com/youth518/p/14130264.html
Copyright © 2011-2022 走看看