NOIP2013D1T3货车运输 (生成树+树链剖分)

给出一个图,询问图上两点间路径上最小的边权。

先跑一次最大生成树。

树剖维护路径最小边权。

树剖又双叒叕写挂了。

  1 #include<cstring>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<cctype>
  6 #define foru(i,x,y) for(int i=x;i<=y;i++)
  7 #define mm(a) memset(a,0,sizeof(a))
  8 #define ford(i,x,y) for(int i=x;i>=y;i--)
  9 #define re(x) x=read()
 10 using namespace std;
 11 typedef long long LL;
 12 typedef double db;
 13 const int inf=1e9;
 14 const int N=2e5+10;
 15 
 16 struct dat{int f,t,w;}a[N],b[N];
 17 struct edge{int to,nxt,w;}e[N];
 18 int head[N],top[N],f[N],F[N],siz[N],t[N*20],son[N],d[N],id[N],ne,nb,n,m,cnt;
 19 
 20 int read(){
 21     static int f,x;static char ch;
 22     x=f=0;ch=getchar();
 23     while(!isdigit(ch)){f=(ch=='-');ch=getchar();}
 24     while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
 25     return f?-x:x;
 26 }
 27 
 28 bool cmp(dat a,dat b){
 29     return a.w>b.w;
 30 }
 31 
 32 int gf(int a){
 33     if(a==F[a])return a;
 34     return F[a]=gf(F[a]);
 35 }
 36 
 37 void add(int a,int b,int c){
 38     e[++ne]=(edge){b,head[a],c};head[a]=ne;
 39     e[++ne]=(edge){a,head[b],c};head[b]=ne;
 40 }
 41 
 42 void dfs(int k,int fa){
 43     f[k]=fa;siz[k]=1;
 44     for(int i=head[k];i;i=e[i].nxt){
 45         int v=e[i].to;
 46         if(v==fa)continue;
 47         d[v]=d[k]+1;
 48         dfs(v,k);
 49         siz[k]+=siz[v];
 50         if(siz[v]>siz[son[k]])son[k]=v;
 51     }
 52 }
 53 
 54 void build(int k,int tp){
 55     id[k]=++cnt;top[k]=tp;
 56     if(son[k])build(son[k],tp);
 57     for(int i=head[k];i;i=e[i].nxt){
 58         int v=e[i].to;
 59         if(v==f[k])continue;
 60         if(v!=son[k])build(v,v);
 61     }
 62 }
 63 
 64 #define mid ((L+R)>>1)
 65 #define ls (k<<1)
 66 #define rs (k<<1|1)
 67 
 68 void upd(int k,int L,int R,int p,int x){
 69     if(p<L||p>R)return;
 70     if(L==R){t[k]=x;return;}
 71     upd(ls,L,mid,p,x);upd(rs,mid+1,R,p,x);
 72     t[k]=min(t[ls],t[rs]);
 73 }
 74 
 75 int quiry(int k,int L,int R,int l,int r){
 76     if(r<L||l>R)return inf;
 77     if(l<=L&&R<=r)return t[k];
 78     return min(quiry(ls,L,mid,l,r),quiry(rs,mid+1,R,l,r));
 79 }
 80 
 81 int find(int a,int b){
 82     int ret=inf;
 83     while(top[a]!=top[b]){
 84         if(d[top[a]]<d[top[b]])swap(a,b);
 85         //又写成了(d[a]<d[b]) 
 86         int tmp=quiry(1,1,cnt,id[top[a]],id[a]);
 87         ret=min(ret,tmp);
 88         a=f[top[a]];
 89     }
 90     if(d[a]<d[b])swap(a,b);
 91     if(a!=b)ret=min(ret,quiry(1,1,cnt,id[b]+1,id[a]));
 92     return ret;
 93 }
 94 
 95 int main(){
 96     scanf("%d%d",&n,&m);
 97     foru(i,1,m){re(a[i].f);re(a[i].t);re(a[i].w);F[i]=i;}
 98     sort(a+1,a+1+m,cmp);
 99     foru(i,1,m){
100         int f1=gf(a[i].f),f2=gf(a[i].t);
101         if(f1!=f2){
102             F[f2]=f1;
103             add(a[i].f,a[i].t,a[i].w);
104             b[++nb]=a[i];
105         }
106     }
107     mm(f);m=n-1;
108     dfs(1,0);
109     build(1,1);
110     foru(i,1,cnt)upd(1,1,cnt,i,inf);
111     foru(i,1,nb){
112         if(d[b[i].f]<d[b[i].t])swap(b[i].f,b[i].t);
113         upd(1,1,cnt,id[b[i].f],b[i].w);
114     }
115     int q=read(),u,v;
116     while(q--){
117         re(u);re(v);
118         if(gf(u)!=gf(v)){puts("-1");continue;}
119         printf("%d\n",find(u,v));
120     }
121     return 0;
122 }

 

转载于:https://www.cnblogs.com/y-m-y/p/7693277.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值