题解 P3250 【[HNOI2016]网络】
这是一道 提高+ 的题目。
题中求不经过某点的最大权路径,
考虑二分答案,问题转化为检验权
考虑线段树维护
那么合并的时候相当于两边的交求交,但是容易发现交都是一条线段或者一个点,所以就是求两条路径的交。
路径
只要这两个点
那么交就是
可以利用如果
那么我们就可以
此时我们可以做到
但是发现二分的过程可以在线段树上完成。
回顾一下我们用到的算法,线段树二分(NOIp2017D2T3),树上路径求交的
但是囿于合并路径的常数(二位数)与复杂度不够优秀的非正解(整体二分+树状数组)的常数相比实在太大。
楼主现学了一发
#include<bits/stdc++.h>
#define maxn 200005
#define lim 19
#define lc u<<1
#define rc u<<1|1
#define mp make_pair
using namespace std;
char cb[1000000],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1000000,stdin),cs==ct)?0:*cs++)
void read(int &res){
char ch;
for(;!isdigit(ch=getc()););
for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
}
char wb[1000000],*wa=wb;
int n,m;
int info[maxn],Prev[maxn],to[maxn],cnt,cnt_e;
pair<int,int>sb[maxn];
void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }
int dat[maxn][4],st[lim][maxn],lg[maxn],pos[maxn],tot,dep[maxn];
void dfs(int u,int ff){
dep[u] = dep[ff] + 1;
st[0][pos[u] = ++tot] = u;
for(int i=info[u];i;i=Prev[i])
if(to[i]!=ff){
dfs(to[i],u);
st[0][++tot] = u;
}
}
inline int Lca(int u,int v){
u = pos[u] , v = pos[v];
if(u > v) swap(u,v);
int t = lg[v-u+1];
return dep[st[t][u]] < dep[st[t][v-(1<<t)+1]] ? st[t][u] : st[t][v-(1<<t)+1];
}
int pt[maxn<<2][2],M;
inline bool cmp(const int &u,const int &v){ return dep[u] > dep[v]; }
inline void merge(int *c,int *a,int *b){
if(a[0] == -1 || b[0] == -1) c[0] = c[1] = -1;
else if(!a[0] || !b[0]) c[0] = a[0] + b[0] , c[1] = a[1] + b[1];
else{
static int p[4] = {};
p[0] = Lca(a[0],b[0]) , p[1] = Lca(a[1],b[1]) , p[2] = Lca(a[1],b[0]) , p[3] = Lca(a[0],b[1]);
sort(p,p+4,cmp);
if(p[0] != p[1]) c[0] = p[0] , c[1] = p[1];
else if(p[0] == Lca(a[0],a[1]) || p[0] == Lca(b[0],b[1])) c[0] = c[1] = p[0] = p[1];
else c[0] = c[1] = -1;
}
}
inline bool chk(int u,int *p){
if(p[0] == -1) return 0;
if(p[0] == 0) return 1;
if(dep[u] < dep[Lca(p[0],p[1])]) return 0;
return Lca(u,p[0]) == u || Lca(u,p[1]) == u;
}
inline void Insert(int pos,int p1,int p2){
pos += M - 1;
for(pt[pos][0] = p1 , pt[pos][1] = p2;pos>1;pos>>=1)
merge(pt[pos>>1],pt[pos],pt[pos^1]);
}
inline int solve(int u,int l,int r,int t){
for(int mid;l<r;){
mid = (l+r) >> 1;
if(chk(t,pt[rc])) u=lc,r = mid;
else u=rc,l = mid+1;
}
return l;
}
void put(int a){
static int q[20]={};
if(a<0) *wa++ = '-' , a = -a;
for(;a;a/=10)q[++q[0]]=a%10;
if(!q[0]) *wa++ = '0';
for(;q[0];) *wa++ = (q[q[0]--] + '0');
}
int main(){
read(n),read(m);
for(int i=1,u,v;i<n;i++){
read(u),read(v);
Node(u,v),Node(v,u);
}
dfs(1,0);
for(int j=1;j<lim;j++)
for(int i=1;i<=tot-(1<<j)+1;i++)
st[j][i] = (dep[st[j-1][i]] < dep[st[j-1][i+(1<<j-1)]] ? st[j-1][i] : st[j-1][i+(1<<j-1)]);
for(int i=2;i<=tot;i++) lg[i] = lg[i>>1] + 1;
for(int i=1;i<=m;i++){
read(dat[i][0]),read(dat[i][1]);
if(dat[i][0] == 0) read(dat[i][2]),read(dat[i][3]),sb[++cnt] = mp(dat[i][3],i);
if(dat[i][0] == 1) dat[i][3] = dat[dat[i][1]][3];
}
sort(sb+1,sb+1+cnt);
for(M=1;M<cnt;M<<=1);
for(int i=1;i<=m;i++){
if(dat[i][0] <= 1)
dat[i][3] = lower_bound(sb+1,sb+1+cnt,mp(dat[i][3],dat[i][0] == 0 ? i : dat[i][1])) - sb;
if(dat[i][0] == 0) Insert(dat[i][3],dat[i][1],dat[i][2]);
if(dat[i][0] == 1) Insert(dat[i][3],0,0);
if(dat[i][0] == 2){
if(chk(dat[i][1],pt[1])) put(-1);
else put(sb[solve(1,1,M,dat[i][1])].first);
*wa++ = '\n';
}
}
fwrite(wb,1,wa-wb,stdout);
}
最后发一张该题的全解法: