关于吸氧能过,不吸氧只有95分这件事,我常数大在哪了???
查看原帖
关于吸氧能过,不吸氧只有95分这件事,我常数大在哪了???
30510
wanghai673楼主2021/10/3 22:21
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
int f[N][22],dis[N],root = 1,dep[N],n,m,cha[N],sum[N];
typedef pair<int,int> P;
struct line{
	int x,y,l,dis;
}road[N];
inline int read()
{
    int p=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
    return f*p;
}
vector<P> v[N];
void dfs1(int s,int d){
	dep[s] = d;
	for(int i = 0;i<v[s].size();++i){
		int to = v[s][i].first,w = v[s][i].second;
		if(to!=f[s][0]){
			sum[to] = w;
			f[to][0] = s;
			dis[to] = dis[s] + w;
			dfs1(to,d+1);
		}
	}
}
inline int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	for(int i = 0;i<22;++i){
		if(((dep[x]-dep[y])>>i)&1){
			x = f[x][i];
		}
	}
	if(x==y)return x;
	for(int i = 21;i>=0;--i){
		if(f[x][i]!=f[y][i]){
			x = f[x][i];
			y = f[y][i];
		}
	}
	return f[x][0];
}
bool cmp(line &a,line &b){
	return a.dis>b.dis;
}
void dfs2(int s){
	for(int i = 0;i<v[s].size();++i){
		int to = v[s][i].first ,w = v[s][i].second;
		if(f[s][0]!=to){
			dfs2(to);
			cha[s] += cha[to];
		}
	}
}
inline bool pd(int mid){
	for(int i = 1;i<=n;++i)cha[i] = 0;
	int cnt = 0;
	for(int i = 1;i<=m;++i){
		if(road[i].dis>mid){
			++cnt;
			cha[road[i].x]++;
			cha[road[i].y]++;
			cha[road[i].l]-=2;
		}
		else break;
	}
	dfs2(root);
	for(int i = 2;i<=n;++i){
		if(cha[i]==cnt&&road[1].dis - sum[i]<=mid){
			return 1;
		} 
	}
	return 0;
}
int main(){
	IOS;
	//freopen("a.txt","r",stdin);
	n = read();
	m = read();
	for(int i = 1;i<=n-1;++i){
		int x,y,z;
		x = read();
		y = read();
		z = read();
		v[x].push_back(P(y,z));
		v[y].push_back(P(x,z));
	}
	dfs1(root,1);
	for(int j = 1;j<22;++j){
		for(int i = 1;i<=n;++i){
			f[i][j] = f[f[i][j-1]][j-1];
		}
	}
	for(int i = 1;i<=m;++i){
		int x,y,l;
		x = read();
		y = read();
		l = lca(x,y);
		road[i].x = x;
		road[i].y = y;
		road[i].l = l;
		road[i].dis = dis[x]+dis[y]-2*dis[l];
	}
	sort(road+1,road+1+m,cmp);
	
	int l = 0,r = road[1].dis;
	// 最小化最大值 
	while(l<r){
		int m = (l+r)>>1;
		if(pd(m)){
			r = m;
		}
		else{
			l = m + 1;
		}
	}
	cout<<r<<endl;
	return 0;
} 

下面是题解的 120ms 我的2s这是怎么回事

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define re register 
using namespace std;
typedef long long ll;
const int inf=1e9+7;
inline int read()
{
    int p=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}
    return f*p;}
const int maxn=300003;
struct Edge
{
    int from,to,w,id;
}p[maxn<<1];
struct query
{
    int x,y,lca,d;
}A[maxn];
int n,m,cnt,head[maxn<<1],C[maxn],dis[maxn];
int fa[maxn],depth[maxn],top[maxn],heavy[maxn],size[maxn];
int val[maxn],dnf[maxn],tot,R,L;
inline void add_edge(int x,int y,int W)//加边 
{
    cnt++;
    p[cnt].from=head[x];
    head[x]=cnt;
    p[cnt].to=y;
    p[cnt].w=W;
}
inline void dfs1(int x,int f)
//树剖dfs1:处理每个点的父亲fa,深度depth,子树大小size,dfs序dnf 
{
    fa[x]=f,depth[x]=depth[f]+1,size[x]=1,dnf[++tot]=x;
    for(re int i=head[x];i;i=p[i].from)
        {
            int y=p[i].to;
            if(y==f)continue;
            val[y]=p[i].w;
            dis[y]=dis[x]+p[i].w;
            dfs1(y,x);
            size[x]+=size[y];
            if(!heavy[x]||size[y]>size[heavy[x]])
                heavy[x]=y;
        }
}
inline void dfs2(int x,int t)//树剖dfs2:处理重链 
{
    top[x]=t;
    if(!heavy[x])return ;
    dfs2(heavy[x],t);
    for(re int i=head[x];i;i=p[i].from)
        {
            int y=p[i].to;
            if(y==fa[x]||y==heavy[x])continue;
            dfs2(y,y);
        }
}
inline int LCA(int x,int y)//树剖求LCA 
{
    while(top[x]!=top[y])
        {
            if(depth[top[x]]<depth[top[y]])swap(x,y);
            x=fa[top[x]];
        }
    return depth[x]<=depth[y]?x:y;
}
//=================================以上是树剖常规操作
inline int check(int lim,int sum=0)//二分答案检验,如上所述 
{
    memset(C,0,sizeof(C));//注意每一次都要清空C数组
    for(re int i=1;i<=m;i++)
        if(A[i].d>lim)//树上(边)差分
            {
                C[A[i].x]++,C[A[i].y]++,C[A[i].lca]-=2;
                sum++;
            }
    for(re int i=n;i>=1;i--)
        {
            C[fa[dnf[i]]]+=C[dnf[i]];//每次差分值都累加到父亲节点
            if(val[dnf[i]]>=R-lim&&C[dnf[i]]==sum)
            //存在一条路径满足上述条件则可行
            	return 1;
        }
    return 0;//否则无解
}
inline int Binary_search(int llim,int rlim,int mid=0)//二分答案 
{
    while(llim<rlim)
        {
            mid=(llim+rlim)>>1;
            if(check(mid))rlim=mid;
            else llim=mid+1;
        }
    return llim;
}
int main()
{
//	freopen("transport.in","r",stdin);
//	freopen("transport.out","w",stdout);
    //这是校内模拟赛的考试题= =光荣爆蛋 
    n=read(),m=read();
    for(re int i=1;i<n;i++)
        {
            int x=read(),y=read(),w=read();
            add_edge(x,y,w);
            add_edge(y,x,w);
            L=max(L,w);//统计最大边权 
        }
    dfs1(1,0);dfs2(1,1);//树剖预处理 
    for(re int i=1;i<=m;i++)//预处理每一次请求的lca和距离 
        {
            A[i].x=read(),A[i].y=read();
            A[i].lca=LCA(A[i].x,A[i].y);
            A[i].d=dis[A[i].x]+dis[A[i].y]-2*dis[A[i].lca];
            R=max(R,A[i].d);
        }
    printf("%d\n",Binary_search(R-L,R+1));//二分答案
    return 0;
}
2021/10/3 22:21
加载中...