Bzoj 4515 线段树 SDOI2016 游戏 Game

本文介绍了一种使用树链剖分进行区间维护的方法,特别关注于如何处理直线相交的问题。文中详细展示了通过递归分解技术来优化查询和更新操作的过程,并提供了具体的C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

树链剖分 区间维护 直线  相交的话判下怎么传即可。。

注意相交上下取整问题 以及一系列long long

我求线段端点 写成了 b*x+b真是愚蠢至极

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
const int N=100010;
const LL INF=123456789123456789LL;
struct Edge{
    int next,v;
    LL w;   
}e[N*2];
int first[N],size[N],fa[N],num,ti,m,
    de[N],dfn[N],id[N],belong[N],n;
LL dis[N],mn[N*4],A[N*4],B[N*4];
bool hastag[N*4];
void add(int u,int v,LL w){
    e[++num].next=first[u];e[num].w=w;
    first[u]=num;e[num].v=v;    
}
void dfs(int x){
    size[x]=1;
    for(int i=first[x];i;i=e[i].next){
        int v=e[i].v;if(de[v]) continue;
        dis[v]=dis[x]+e[i].w;de[v]=de[x]+1;
        fa[v]=x;dfs(v);size[x]+=size[v];    
    }   
}
void dfs(int x,int chain){
    dfn[x]=++ti;id[ti]=x;
    belong[x]=chain;int k=0;
    for(int i=first[x];i;i=e[i].next){
        int v=e[i].v;
        if(de[v]<de[x]) continue;    
        if(size[v]>size[k]) k=v;
    }
    if(!k) return;dfs(k,chain);
    for(int i=first[x];i;i=e[i].next){
        int v=e[i].v;
        if(de[v]<de[x]||k==v) continue;
        dfs(v,v);   
    }
}
int Lca(int u,int v){
    while(belong[u]!=belong[v]){
        if(de[belong[u]]<de[belong[v]]) swap(u,v);
        u=fa[belong[u]];
    }   
    return de[u]<de[v]?u:v;
}
void update(int x,int l,int r){
    if(hastag[x]) mn[x]=min(A[x]*dis[id[l]],A[x]*dis[id[r]])+B[x];  
    if(l!=r) mn[x]=min(mn[x],min(mn[2*x],mn[2*x+1]));
}
void Add2(int x,int l,int r,LL a,LL b){
	
    if(!hastag[x]){
        hastag[x]=1;A[x]=a;B[x]=b;update(x,l,r);return;
    }
    int mid=(l+r)>>1;
    LL x1=A[x]*dis[id[l]]+B[x],y1=A[x]*dis[id[r]]+B[x],
       x2=a*dis[id[l]]+b,y2=a*dis[id[r]]+b;
	   //cout<<x<<" "<<l<<" "<<r<<" "<<a<<" "<<b<<" ";cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<endl;
    if(x2<=x1&&y2<=y1) {A[x]=a;B[x]=b;}
    else if(x2>=x1&&y2>=y1)return;
    else if(a<A[x]){
        LL tmp=(b-B[x])/(A[x]-a)+1;
        if(tmp<=dis[id[mid]]){
            swap(a,A[x]);swap(b,B[x]);
            Add2(2*x,l,mid,a,b);
        }   
        else Add2(2*x+1,mid+1,r,a,b);
    }
    else {
    //	if(a==A[x]) cout<<x1<<" "<<x2<<" "<<y1<<" "<<y2<<endl;
        LL tmp=(b-B[x]-1)/(A[x]-a); 
        if(tmp>dis[id[mid]]){
            swap(A[x],a);swap(B[x],b);
            Add2(2*x+1,mid+1,r,a,b);
        }
        else Add2(2*x,l,mid,a,b);
    }
	update(x,l,r);
}
void Add1(int x,int l,int r,int _l,int _r,LL a,LL b){
    if(_l<=l&&r<=_r){
        Add2(x,l,r,a,b);    
    }
    else {
        int mid=(l+r)>>1;
        if(_l<=mid) Add1(2*x,l,mid,_l,_r,a,b);
        if(_r>mid) Add1(2*x+1,mid+1,r,_l,_r,a,b);    
    }
    update(x,l,r);
}
void Tree_Add2(int s,int t,LL a,LL b){
    while(belong[s]!=belong[t]){
        int pnt=belong[s];
        Add1(1,1,n,dfn[pnt],dfn[s],a,b);
        s=fa[belong[s]];
    }
  //  cout<<dfn[t]<<" "<<dfn[s]<<" "<<s<<" "<<t<<"!!!"<<endl;
    Add1(1,1,n,dfn[t],dfn[s],a,b);
}
void Tree_Add1(int s,int t,LL a,LL b){
    int lc=Lca(s,t);
    Tree_Add2(s,lc,-a,b+a*dis[s]);
    Tree_Add2(t,lc,a,b+a*(dis[s]-2*dis[lc]));   
}
LL Ask(int x,int l,int r,int _l,int _r){
    if(_l<=l&&r<=_r) return mn[x];
    LL res=mn[0];
    if(hastag[x]) {
        int ll=max(_l,l),rr=min(_r,r);
        res=min(res,min(A[x]*dis[id[ll]],A[x]*dis[id[rr]])+B[x]);
    }
    int mid=(l+r)>>1;
    if(_l<=mid) res=min(res,Ask(2*x,l,mid,_l,_r));
    if(_r>mid) res=min(res,Ask(2*x+1,mid+1,r,_l,_r));
    return res; 
}
LL Tree_Ask2(int s,int t){
    LL res=mn[0];
    while(belong[s]!=belong[t]){
        res=min(res,Ask(1,1,n,dfn[belong[s]],dfn[s]));
        s=fa[belong[s]];
    }
    return min(res,Ask(1,1,n,dfn[t],dfn[s]));
}
LL Tree_Ask1(int s,int t){
    int lc=Lca(s,t);
    return min(Tree_Ask2(s,lc),Tree_Ask2(t,lc));    
}
void print(int x,int l,int r){
	cout<<x<<" "<<l<<" "<<r<<" "<<A[x]<<" "<<B[x]<<" "<<mn[x]<<endl;
	if(l==r) return;
	int mid=(l+r)>>1;
	print(2*x,l,mid);
	print(2*x+1,mid+1,r);	
}
int read(){
    int x=0,fu=1; char ch=getchar();
    while (ch<'0' || ch>'9'){ if (ch=='-') fu=-1; ch=getchar(); }
    while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
    return x*fu;
}
int main(){
	n=read(),m=read();
    //scanf("%d%d",&n,&m);
	LL w;
    for(int i=1,a,b;i<n;i++){
    	a=read();b=read();w=read();
        add(a,b,w);add(b,a,w);  
    }de[1]=1;
    dfs(1);dfs(1,1);
  //  for(int i=1;i<=n;i++)
    //   cout<<dfn[i]<<" "<<belong[i]<<endl;
    //cout<<"!"<<endl;
    int k=0;
    for(int i=0;i<=4*n;i++) mn[i]=INF;
    int Type,s,t;LL a,b;
    while(m--){
        Type=read();
		//scanf("%d",&Type);
        if(Type==1){
        	s=read();t=read();a=read();b=read();
           // scanf("%d%d%lld%lld",&s,&t,&a,&b);
            Tree_Add1(s,t,a,b);
        }
        else {
        	k++;
        	s=read();t=read();
           // scanf("%d%d",&s,&t);
        	//cout<<s<<" "<<t<<" "<<Lca(s,t)<<endl;
            printf("%lld\n",Tree_Ask1(s,t));   
        	Tree_Ask1(s,t);
     		//if(k==134)  print(1,1,n);
		}
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值