把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

CF gym102803 E. Everybody Lost Somebody

题面传送门

首先树上问题考虑点分,但是问题在于无法将询问简单地仅下放到单侧子树内,换言之每个询问可能在 \(O(n)\) 次点分时被计算入答案。

这显然不太好,我们考虑提取一些关键点对使得答案被包含在其中。

考虑单次点分的时候怎么计算单次询问的答案,显然是区间最小值加次小值。这里不用考虑两者是否在同一个子树内,因为边权为正,在同一子树内一定不优。

考虑枚举次小值的位置,然后找到这个位置两边第一个比它小的位置,显然再往左要么最小值次小值发生改变,就不符合定义,要么不变的情况下区间变大不会更优。因此我们可以用两倍点数个区间来得到答案。

所以在点分的过程中得到 \(O(n\log n)\) 个点对,扫描线加上树状数组即可做到 \(O(n\log ^2n+q\log n)\)

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=2e5+5,M=1e6+5,K=50+5,mod=998244353,Mod=mod-1;const db eps=1e-9;const int INF=1e9+7;mt19937 rnd(time(0));
int st[N],sh,n,m,k,x,y,z,Rt,Ct,Si[N],dp[N],vis[N],Bh;ll Ans[M];
struct Edge{int to,w;};vector<Edge> S[N]; 
struct Node{int x;ll w;}B[N];vector<Node> P[N];bool cmp(Node x,Node y){return x.x<y.x;}
struct Ques{int x,id;};vector<Ques> Q[N];
void GI(int x,int La){Si[x]=1;for(Edge i:S[x]) i.to^La&&!vis[i.to]&&(GI(i.to,x),Si[x]+=Si[i.to]);}
void DP(int x,int La){dp[x]=Ct-Si[x];for(Edge i:S[x]) i.to^La&&!vis[i.to]&&(DP(i.to,x),dp[x]=max(dp[x],Si[i.to]));dp[x]<dp[Rt]&&(Rt=x);}
void Make(int x,int La,ll w){B[++Bh]=(Node){x,w};for(Edge i:S[x]) i.to^La&&!vis[i.to]&&(Make(i.to,x,w+i.w),0);}
void dfs(int x){
	GI(x,0);Ct=Si[x];dp[Rt=0]=INF;DP(x,0);vis[x=Rt]=1;assert(dp[x]*2<=Ct);
	B[Bh=1]=(Node){x,0};for(Edge i:S[x]) !vis[i.to]&&(Make(i.to,x,i.w),0);int i;sort(B+1,B+Bh+1,cmp);
	sh=0;for(i=1;i<=Bh;i++) {while(sh&&B[st[sh]].w>B[i].w) sh--;if(sh)P[min(B[i].x,B[st[sh]].x)].PB((Node){max(B[i].x,B[st[sh]].x),B[i].w+B[st[sh]].w});st[++sh]=i;}
	sh=0;for(i=Bh;i;i--){while(sh&&B[st[sh]].w>B[i].w) sh--;if(sh)P[min(B[i].x,B[st[sh]].x)].PB((Node){max(B[i].x,B[st[sh]].x),B[i].w+B[st[sh]].w});st[++sh]=i;}	
	for(Edge i:S[x]) !vis[i.to]&&(dfs(i.to),0);
}
namespace BIT{
	ll f[N];void Ins(int x,ll w){while(x<=n) f[x]=min(f[x],w),x+=x&-x;}
	ll Qry(int x){ll Ans=1e18+7;while(x) Ans=min(Ans,f[x]),x-=x&-x;return Ans;}
}
int main(){
	freopen("1.in","r",stdin);
	int i,j;scanf("%d",&n);for(i=1;i<n;i++) scanf("%d%d%d",&x,&y,&z),S[x].PB((Edge){y,z}),S[y].PB((Edge){x,z});
	dfs(1);Me(BIT::f,0x3f);scanf("%d",&m);for(i=1;i<=m;i++) scanf("%d%d",&x,&y),Q[x].PB((Ques){y,i});
	for(i=n;i;i--) {for(Node j:P[i]) BIT::Ins(j.x,j.w);for(Ques j:Q[i]) Ans[j.id]=BIT::Qry(j.x);}
	for(i=1;i<=m;i++) printf("%lld\n",Ans[i]>=1e16?-1:Ans[i]);
}
posted @ 2023-02-15 15:56  275307894a  阅读(50)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end