どこでもドア
边分治模板题,点分也可以做啊。
//Achen
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define For(i,a,b) for(register int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(register int i=(a);i>=(b);i--)
#define Formylove return 0
typedef long long LL;
typedef double db;
const int N=50007*1.5;
using namespace std;
int n,v[N],tot;
LL ans;
template<typename T> void read(T &x) {
char ch=getchar(); T f=1; x=0;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
int ecnt,fir[N],nxt[N<<1],to[N<<1],val[N<<1];
void add(int u,int v,int w) {
nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w;
}
vector<int>son[N];
void dfs1(int x,int fa) {
for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
son[x].push_back(to[i]);
dfs1(to[i],x);
}
}
void rebuild() {
dfs1(1,0);
tot=n;
For(x,1,n) fir[x]=0; ecnt=1;
For(x,1,tot) {
int szz=son[x].size();
if(szz<=2) {
For(i,0,szz-1)
add(x,son[x][i],(son[x][i]<=n));
}
else {
int t1=++tot,t2=++tot;
v[t1]=v[t2]=v[x];
add(x,t1,0); add(x,t2,0);
For(i,0,szz-1) {
if(i&1) son[t1].push_back(son[x][i]);
else son[t2].push_back(son[x][i]);
}
}
}
}
int H[N],R[N];
bool cmp(const int &A,const int &B) {
return H[A]>H[B];
}
int vis[N],t[2][N],o[2];
void dfs2(int x,int fa,int id) {
if(!fa) {
o[id]=0; R[x]=0; H[x]=v[x];
}
t[id][++o[id]]=x;
for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa&&!vis[i>>1]) {
R[to[i]]=R[x]+val[i];
H[to[i]]=min(H[x],v[to[i]]);
dfs2(to[i],x,id);
}
}
int sz[N],mxson[N],rt,eg;
void get_rt(int x,int fa,int SZ) {
sz[x]=1;
for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa&&!vis[i>>1]) {
get_rt(to[i],x,SZ);
sz[x]+=sz[to[i]];
if(!rt||mxson[to[i]]<mxson[rt]) {
rt=x; eg=i;
}
}
mxson[x]=max(sz[x],SZ-sz[x]);
}
void solve(int x,int SZ) {
rt=0; get_rt(x,0,SZ);
if(!rt) return ;
vis[eg>>1]=1;
x=rt; int y=to[eg];
dfs2(x,0,0); dfs2(y,0,1);
sort(t[0]+1,t[0]+o[0]+1,cmp);
sort(t[1]+1,t[1]+o[1]+1,cmp);
int mx1=0,mx2=0,l=1;
For(i,1,o[0]) {
mx1=max(mx1,R[t[0][i]]);
while(l<=o[1]&&H[t[1][l]]>=H[t[0][i]]) { mx2=max(mx2,R[t[1][l]]); l++; }
if(l>1) ans=max(ans,(1LL+val[eg]+mx1+mx2)*H[t[0][i]]);
}
mx1=0,mx2=0,l=1;
For(i,1,o[1]) {
mx1=max(mx1,R[t[1][i]]);
while(l<=o[0]&&H[t[0][l]]>=H[t[1][i]]) { mx2=max(mx2,R[t[0][l]]); l++; }
if(l>1) ans=max(ans,(1LL+val[eg]+mx1+mx2)*H[t[1][i]]);
}
solve(x,SZ-sz[y]); solve(y,sz[y]);
}
int main() {
//freopen("1.in","r",stdin);
//freopen(".out","w",stdout);
read(n);
For(i,1,n) read(v[i]);
For(i,2,n) {
int x,y;
read(x); read(y);
add(x,y,0);
}
rebuild();
solve(1,tot);
printf("%lld\n",ans);
//cerr<
Formylove;
}
どこでもドア
题解
大概就是,在第一棵树上边分治,把每次分治处理的点拿出来在第二棵树上建虚树,并按在分治边的左右染色。在虚树上枚举所有的lca,把这个lca的子树中的点在第一棵树中求直径,用不同色的直径更新答案。直径可合并。
//Achen
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define For(i,a,b) for(register int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(register int i=(a);i>=(b);i--)
#define Formylove return 0
const int N=4e5+7;
typedef long long LL;
typedef double db;
using namespace std;
int n;
LL ans;
template<typename T> void read(T &x) {
char ch=getchar(); T f=1; x=0;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
vector<int>son[N<<2];
vector<LL>edge[N<<2];
struct Graph {
int ecnt,fir[N],nxt[N<<1],to[N<<1],an[N];
LL val[N<<2];
void add(int u,int v,LL w) {
nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w;
}
int R[N],dfn[N],tid[N],dfk,dfn2[N],dfk2,sz[N];
LL H[N];
void dfs1(int x,int Fa) {
sz[x]=1;
R[x]=R[Fa]+1;
tid[++dfk2]=x;
dfn2[x]=dfk2;
dfn[x]=++dfk;
for(int i=fir[x];i;i=nxt[i]) if(to[i]!=Fa) {
H[to[i]]=H[x]+val[i];
dfs1(to[i],x);
tid[++dfk2]=x;
sz[x]+=sz[to[i]];
}
}
int st[N][20];
void make_st() {
For(i,0,17) For(x,1,n<<1) if(x+(1<<i)-1<=(n<<1)){
if(i==0) st[x][i]=tid[x];
else {
int a=st[x][i-1],b=st[x+(1<<i-1)][i-1];
st[x][i]=(R[a]<=R[b]?a:b);
}
}
}
int lca(int x,int y) {
if(x==y) {
//printf("%d\n",x);
return x;
}
int l=dfn2[x],r=dfn2[y],k=0;
if(l>r) swap(l,r);
while(l+(1<<k)-1<=r) k++; if(k) k--;
int a=st[l][k],b=st[r-(1<<k)+1][k];
int rs=R[a]<=R[b]?a:b;
//printf("%d\n",rs);
return rs;
}
int in(int a,int b) { return dfn[a]>=dfn[b]&&dfn[a]<dfn[b]+sz[b]; }
LL dis(int x,int y) { return H[x]+H[y]-2LL*H[lca(x-n,y-n)]; }
int tot;
void dfs2(int x,int fa) {
for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
son[x].push_back(to[i]);
edge[x].push_back(val[i]);
dfs2(to[i],x);
}
}
void lik() {
For(i,1,n) {
R[i+n]=R[i]+1;
//f[i+n][0]=i;
//For(j,1,16) f[i+n][j]=f[f[i+n][j-1]][j-1];
add(i,i+n,0);
an[i]=ecnt-1;
}
}
void rebuild() {
dfs2(1,0);
tot=n;
For(x,1,n) fir[x]=0; ecnt=1;
For(x,1,tot) {
int szz=son[x].size();
if(szz<=2) {
For(i,0,szz-1)
add(x,son[x][i],edge[x][i]);
}
else {
int t1=++tot,t2=++tot;
add(x,t1,0); add(x,t2,0);
For(i,0,szz-1) {
if(i&1) {
son[t1].push_back(son[x][i]);
edge[t1].push_back(edge[x][i]);
}
else {
son[t2].push_back(son[x][i]);
edge[t2].push_back(edge[x][i]);
}
}
}
}
}
}G[3];
int tim;
struct XUT {
int ecnt,fir[N],nxt[N<<1],to[N<<1],tag[N];
LL g[N][2][2],mx[N][2],tpans;
void add(int u,int v) {
nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; //val[ecnt]=w;
//nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w;
}
void merge(int x,int y) {
For(a,0,1) For(b,0,1) {
if(g[x][0][a]&&g[y][1][b]) tpans=max(tpans,G[1].dis(g[x][0][a]+n,g[y][1][b]+n)-2LL*G[0].H[x]);
if(g[x][1][a]&&g[y][0][b]) tpans=max(tpans,G[1].dis(g[x][1][a]+n,g[y][0][b]+n)-2LL*G[0].H[x]);
}
For(i,0,1) {
int a=g[x][i][0],b=g[x][i][1]; LL mxx=mx[x][i];
if(!a||mxx<mx[y][i]) a=g[y][i][0],b=g[y][i][1],mxx=mx[y][i];
For(u,0,1) if(g[x][i][u]) For(v,0,1) if(g[y][i][v]){
LL tpp=G[1].dis(g[x][i][u]+n,g[y][i][v]+n);
if(!a||tpp>mxx) {
a=g[x][i][u]; b=g[y][i][v]; mxx=tpp;
}
}
g[x][i][0]=a; g[x][i][1]=b; mx[x][i]=mxx;
}
}
void dfs(int x) {
memset(g[x],0,sizeof(g[x])); mx[x][0]=mx[x][1]=mx[x][2]=0;
if(tag[x]==tim+1) g[x][0][0]=g[x][0][1]=x;
else if(tag[x]==tim+2) g[x][1][0]=g[x][1][1]=x;
for(int i=fir[x];i;i=nxt[i]) {
dfs(to[i]);
merge(x,to[i]);
}
}
LL solve() {
tpans=0;
dfs(1);
return tpans;
}
}X;
bool cmp(const int &A,const int &B) { return G[0].dfn[A]<G[0].dfn[B]; }
struct sol {
int sz[N],mxson[N],rt,nowsz,eg,vis[N];
void get_rt(int x,int fa,int SZ) {
sz[x]=1;
for(int i=G[2].fir[x];i;i=G[2].nxt[i]) {
int y=G[2].to[i];
if(y==fa||vis[i>>1]) continue;
get_rt(y,x,SZ);
sz[x]+=sz[y];
if(!rt||mxson[y]<nowsz) {
rt=x; nowsz=mxson[y]; eg=i;
}
}
mxson[x]=max(sz[x],SZ-sz[x]);
}
int sta[N],top;
LL R[N];
void dfs(int x,int fa,int tg) {
X.tag[x]=tg;
if(!fa) R[x]=0;
if(x<=n) {
sta[++top]=x;
G[1].val[G[1].an[x]]=R[x]+G[0].H[x];
G[1].H[x+n]=G[1].H[x]+R[x]+G[0].H[x];
G[1].val[G[1].an[x]+1]=R[x]+G[0].H[x];
}
for(int i=G[2].fir[x];i;i=G[2].nxt[i]) {
int y=G[2].to[i];
if(y==fa||vis[i>>1]) continue;
R[y]=R[x]+G[2].val[i];
dfs(y,x,tg);
}
}
int sta2[N],top2;
LL work() {
sort(sta+1,sta+top+1,cmp);
int up=top-1;
For(i,1,up) sta[++top]=G[0].lca(sta[i],sta[i+1]);
sta[++top]=1;
sort(sta+1,sta+top+1,cmp);
up=unique(sta+1,sta+top+1)-(sta+1);
For(i,1,up) X.fir[sta[i]]=0; X.ecnt=0;
top2=0;
For(i,1,up) {
while(top2&&!G[0].in(sta[i],sta2[top2])) top2--;
if(top2) X.add(sta2[top2],sta[i]);
sta2[++top2]=sta[i];
}
return X.solve();
}
void solve(int x,int SZ) {
rt=0;
get_rt(x,0,SZ);
if(!rt) return ;
vis[eg>>1]=1;
x=rt; int y=G[2].to[eg];
top=0;
dfs(x,0,tim+1); dfs(y,0,tim+2);
ans=max(ans,G[2].val[eg]+work());
tim+=2;
solve(x,SZ-sz[y]); solve(y,sz[y]);
}
}S;
int main() {
//freopen("rand.txt","r",stdin);
read(n);
For(o,0,2) For(i,2,n) {
int x,y; LL w;
read(x); read(y); read(w);
G[o].add(x,y,w);
}
G[0].dfs1(1,0);
G[0].make_st();
G[1].dfs1(1,0);
G[1].make_st();
G[1].lik();
G[2].rebuild();
S.solve(1,G[2].tot);
printf("%lld\n",ans);
Formylove;
}
どこでもドア
听说是边分,感觉可以边分虚树dp?
然后去看了下题解,神仙们说把式子化一化,
( R x + R y + d i s ( x , y ) ) / 2 − d i s ′ ( x , y ) (R_x+R_y+dis(x,y))/2-dis'(x,y) (Rx+Ry+dis(x,y))/2−dis′(x,y)
第二棵树上的lca没法处理,只能枚举。然后第一棵树上询问子树中点的距离最大值。发现通道那题的合并直径不资磁负数,考虑用边分治找距离最大值。发现边分树是棵二叉树可以类似线段树合并合并边分树,合并的同时也就计算答案了。
然鹅我的写法太不优秀空间有点爆炸,一边updata一边清空vector才不会爆空间。。
//Achen
#include
#define For(i,a,b) for(register int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(register int i=(a);i>=(b);i--)
#define Formylove return 0
const int N=2*366666+7;
typedef long long LL;
typedef double db;
using namespace std;
int n;
LL ans;
template<typename T> void read(T &x) {
char ch=getchar(); T f=1; x=0;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
int ecnt,fir[N],nxt[N<<1],fr[N<<1],to[N<<1];
LL val[N<<1],R1[N];
void add(int u,int v,LL w) {
nxt[++ecnt]=fir[u]; fir[u]=ecnt; fr[ecnt]=u; to[ecnt]=v; val[ecnt]=w;
nxt[++ecnt]=fir[v]; fir[v]=ecnt; fr[ecnt]=v; to[ecnt]=u; val[ecnt]=w;
}
#define pr pair
#define MP make_pair
#define se second
#define fi first
vector<pr>son[N];
void prebuild(int x,int fa) {
for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
son[x].push_back(MP(to[i],val[i]));
prebuild(to[i],x);
}
}
int bvs[N],cnt;
void rebuild(int x) {
bvs[x]=1;
int up=son[x].size();
if(up<=2) For(i,0,up-1) add(x,son[x][i].fi,son[x][i].se);
else {
For(i,0,up-1) {
if(i&1) up>3?son[cnt+2].push_back(son[x][i]):add(x,son[x][i].fi,son[x][i].se);
else son[cnt+1].push_back(son[x][i]);
}
add(x,++cnt,0); if(up>3) add(x,++cnt,0);
}
for(int i=fir[x];i;i=nxt[i]) if(!bvs[to[i]]) {
R1[to[i]]=R1[x]+val[i];
rebuild(to[i]);
}
}
int RT,eg,sz[N],msz[N],vis[N<<1];
void get_root(int x,int fa,int tot) {
sz[x]=1;
for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa&&!vis[i]) {
get_root(to[i],x,tot);
sz[x]+=sz[to[i]];
if(!RT||msz[to[i]]<msz[RT]) RT=to[i],eg=i;
}
msz[x]=max(sz[x],tot-sz[x]);
}
vector<int>bl[N];
vector<LL>ds[N];
void dfs1(int x,int fa,int BL,LL R) {
sz[x]=1;
if(x<=n) {
bl[x].push_back(BL);
ds[x].push_back(R+R1[x]);
}
for(int i=fir[x];i;i=nxt[i]) if(!vis[i]&&to[i]!=fa) {
dfs1(to[i],x,BL,R+val[i]);
sz[x]+=sz[to[i]];
}
}
int trt,ls[N<<1],rs[N<<1];
int build(int x,int tot) {
if(tot<2) return 0;
RT=0; get_root(x,0,tot);
int id=eg;
vis[id]=vis[id^1]=1;
dfs1(fr[id],0,0,0);
ls[id]=build(fr[id],sz[fr[id]]);
dfs1(to[id],0,1,0);
rs[id]=build(to[id],sz[to[id]]);
return id;
}
LL mx[N*20][2];
int tot,rt[N],ch[N*20][2];
#define lc ch[x][0]
#define rc ch[x][1]
#define inf 1e17
void upd(int &x,int y,int D) {
if(!x) {
x=++tot;
mx[x][0]=mx[x][1]=-inf;
}
int l=bl[y][D];
mx[x][l]=max(mx[x][l],ds[y][D]);
int up=bl[y].size();
if(D+1==up) return;
upd(ch[x][l],y,D+1);
}
LL Qrs;
int merge(int x,int y,int nx) {
if(!(x*y)) return (x^y);
For(i,0,1) Qrs=max(Qrs,mx[x][i]+mx[y][i^1]+val[nx]);
For(i,0,1) mx[x][i]=max(mx[x][i],mx[y][i]);
lc=merge(lc,ch[y][0],ls[nx]);
rc=merge(rc,ch[y][1],rs[nx]); return x;
}
int ec,fi[N],nx[N<<1],tt[N<<1];
LL va[N<<1];
void ADD(int u,int v,LL w) {
nx[++ec]=fi[u]; fi[u]=ec; tt[ec]=v; va[ec]=w;
nx[++ec]=fi[v]; fi[v]=ec; tt[ec]=u; va[ec]=w;
}
void dfs2(int x,int fa,LL dep) {
for(int i=fi[x];i;i=nx[i]) if(tt[i]!=fa)
dfs2(tt[i],x,dep+va[i]);
Qrs=-inf;
for(int i=fi[x];i;i=nx[i]) if(tt[i]!=fa)
rt[x]=merge(rt[x],rt[tt[i]],trt);
ans=max(ans,Qrs/2-dep);
ans=max(ans,R1[x]-dep);
}
int main() {
//freopen("std.in","r",stdin);
//freopen("WA.out","w",stdout);
read(n);
For(i,2,n) {
int u,v,w;
read(u); read(v); read(w);
add(u,v,w);
}
prebuild(1,0);
cnt=n; ecnt=1;
memset(fir,0,sizeof(fir));
rebuild(1);
trt=build(1,cnt);
For(i,2,n) {
int u,v,w;
read(u); read(v); read(w);
ADD(u,v,w);
}
For(i,1,n) {
upd(rt[i],i,0);
ds[i].clear(); bl[i].clear();
}
dfs2(1,0,0);
printf("%lld\n",ans);
Formylove;
}