LGP2680
7.15号,一天的时间耗在这个题上,ennn,反思总结.
1.玄学编译错误:一定要注意结构体的空间大小.
2.关于求树任意两点距离:用dis数组记录根节点到每一点距离,对于from,to
两点,用dis[from]+dis[to]-2*dis[LCA]即可求得树上两点距离,o(m)遍历便可,
今天用最短路dj求树上两点,o((n+m)*log(m))则不值.
3.板子一定要打稳,LCA今天调了很多次.
4.get求线段并的差分方法.
1.暴力
显然我们可以想到暴力枚举边权为零,再算出对m个计划的影响,求m个计划的最大时间中的最小值
要注意dis数组的使用,不要sb地用最短路,树上路线唯一确定.
2.正解.
1.对于最大值最小问题,我们会想到二分答案.将ans定义为能询问路径中合法存在的最长路径,我
们的任务就是将ans不断缩小.将询问路径中长度比ans大的找出来.可以这样理解,maxdis是我们
期望的最长最小,对那些比它长的路径我们希望通过虫洞减少,只有长的才对'最长路径'有影响.所以
我们找出最长的长出maxdis多长,看能不能通过虫洞消除,若能消除则一定有合法的更小值.若不能
则只能maxdis变长,对用虫洞去消长度的要求小一点.
2.如何用虫洞消?一定消比它长度的路径的交集路径的最大值.因为一定要影响整体,整体一个不合
法,maxdis就一定扩大,这就是为什么用最长的减最maxdis,因为我希望都合法,maxdis才缩小
3.如何去路径并?先考虑线段并,暴力染色看染色次数?线段树O(logn)维护?其实可以用差分.将线段
的l设置为1,r的后一位为-1,求一遍前缀和的过程中能得到每个点被覆盖次数.可理解为在线段区间
我们用1体现线段区间(区间两字用前缀和体现)染色,-1则体现消除影响(因为脱离区间).那么树上的
两点的距离可看做两点到LCA的两条线段,(num[LCA]-=2即这个意思).当覆盖次数等于加入线段个
数即表示它被所有区间覆盖,我们要求的虫洞即在这.
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 #define e exit(0) 6 #define R register 7 #define ll long long 8 const int maxn=3*1e6+10; 9 long long n,m,cnt,l,r,deep,dfn[maxn],num[maxn],h[maxn],fa[maxn],dis[maxn],head[maxn],bz[maxn][24]; 10 struct bian{ 11 ll to,next,v; 12 }len[maxn<<1]; 13 struct kkk{ 14 ll from,to,lcaa,diss; 15 }ask[maxn<<1]; 16 inline long long fd() 17 { 18 long long s=1,t=0; 19 char c=getchar(); 20 while(c<'0'||c>'9') 21 { 22 if(c=='-') 23 s=-1; 24 c=getchar(); 25 } 26 while(c>='0'&&c<='9') 27 { 28 t=t*10+c-'0'; 29 c=getchar(); 30 } 31 return s*t; 32 } 33 void add(ll from,ll to,ll v) 34 { 35 len[++cnt].v=v; 36 len[cnt].to=to; 37 len[cnt].next=head[from]; 38 head[from]=cnt; 39 } 40 void dfs(ll x) 41 { 42 dfn[++deep]=x; 43 for(R ll k=head[x];k;k=len[k].next) 44 { 45 ll to=len[k].to; 46 if(!h[to]) 47 { 48 h[to]=h[x]+1; 49 fa[to]=x; 50 dfs(to); 51 } 52 } 53 } 54 void makebz() 55 { 56 h[1]=1,fa[1]=1; 57 dfs(1); 58 for(R ll i=1;i<=n;++i) 59 bz[i][0]=fa[i]; 60 for(R ll j=1;j<=19;++j) 61 for(R ll i=1;i<=n;++i) 62 bz[i][j]=bz[bz[i][j-1]][j-1]; 63 } 64 long long LCA(ll x,ll y) 65 { 66 if(h[x]<=h[y]) 67 swap(x,y); 68 for(R ll k=19;k>=0;--k) 69 if(h[bz[x][k]]>=h[y]) 70 x=bz[x][k]; 71 if(x==y) 72 return x; 73 for(R ll k=19;k>=0;--k) 74 if(bz[x][k]!=bz[y][k]) 75 x=bz[x][k],y=bz[y][k]; 76 return fa[x]; 77 } 78 void dfsdis(ll x,ll sum,ll fa) 79 { 80 for(R ll k=head[x];k;k=len[k].next) 81 { 82 ll to=len[k].to,v=len[k].v; 83 if(to==fa) continue; 84 ll nowsum=sum+v; 85 dis[to]=nowsum; 86 dfsdis(to,nowsum,x); 87 } 88 } 89 bool check(ll mid) 90 { 91 ll cnt=0,maxdis=0; 92 memset(num,0,sizeof(num)); 93 for(R ll i=1;i<=m;++i) 94 { 95 if(ask[i].diss>mid) 96 { 97 ll from=ask[i].from,to=ask[i].to,lca=ask[i].lcaa; 98 ++num[from],++num[to],num[lca]-=2; 99 maxdis=max(maxdis,ask[i].diss-mid); 100 ++cnt; 101 } 102 } 103 if(cnt==0) 104 return true; 105 for(R ll i=n;i>=1;--i) 106 num[fa[dfn[i]]]+=num[dfn[i]]; 107 for(R ll i=2;i<=n;++i) 108 if(num[i]==cnt&&dis[i]-dis[fa[i]]>=maxdis) 109 return true; 110 return false; 111 } 112 int main() 113 { 114 // freopen("s.in","r",stdin); 115 // freopen("s.out","w",stdout); 116 n=fd(),m=fd(); 117 for(R ll i=1;i<n;++i) 118 { 119 ll from=fd(),to=fd(),v=fd(); 120 add(from,to,v),add(to,from,v); 121 r+=v; 122 } 123 makebz(); 124 dfsdis(1,0,1); 125 for(R ll i=1;i<=m;++i) 126 { 127 ll from=fd(),to=fd(); 128 ask[i].from=from,ask[i].to=to; 129 ask[i].lcaa=LCA(from,to),ask[i].diss=dis[from]+dis[to]-2*dis[ask[i].lcaa]; 130 } 131 while(l<r) 132 { 133 ll mid=(l+r)>>1; 134 if(check(mid)) r=mid; 135 else l=mid+1; 136 } 137 printf("%lld",l); 138 return 0; 139 }