辺分治
178855 ワード
記事の目次 bzoj 2870.最長道路tree uoj 347.【WC 2018】チャネル [CTSC2018]暴力書き込み -------3.14 up----------
今日書きながら分治した時、このブログのトップ3のテンプレートが間違っていたことに気づきました.ゲットするrootの時はszより問題があります.
bzoj 2870.一番長い道路tree
どのようなものですか?もしドゥア側でテンプレートの問題を分けて、ポイントをつけてもいいです.
子供でもドゥアというのは、1本目の木の上で分割して、処分するたびにポイントを取り出して、2本目の木に虚木を建て、分治辺の左右を押して染めるということです.虚木の上ですべてのlcaを列挙して、このlcaの子木の中の点を第一本の木の中で直径を求めて、異なった色の直径で解答を更新します.直径はマージ可能です
どちらでもドゥアはサイドと聞いていますが、虚樹dpを分けながらもいいと思いますか?次に題解を見に行きましたが、神様たちは式子化すると言いました.(R x+R y+d_i s(x,y)/2−d_i s’(x,y)(Rux+Ruy+dis(x,y)/2−dis'(x,y)(Rx+Ry+dis(x,y)/2 dily)は、2番目の列挙しかできません.そして一番目の木に、サブツリーの中でポイントの距離が一番大きいかを尋ねます.チャンネルの問題を発見した合併直径は磁気負によらず、辺分治で距離の最大値を探すことを考えています.辺分木は二叉の木で、線分樹のように合併して分木することができます.ガチョウの書き方があまりにも優秀ではないので、空間がちょっと爆発します.
今日書きながら分治した時、このブログのトップ3のテンプレートが間違っていたことに気づきました.ゲットするrootの時はszより問題があります.
bzoj 2870.一番長い道路tree
どのようなものですか?もしドゥア側でテンプレートの問題を分けて、ポイントをつけてもいいです.
//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
",ans);
//cerr<
Formylove;
}
uoj 347.【WC 2018】チャンネル子供でもドゥアというのは、1本目の木の上で分割して、処分するたびにポイントを取り出して、2本目の木に虚木を建て、分治辺の左右を押して染めるということです.虚木の上ですべての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
",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
",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
",ans);
Formylove;
}
[CTSC 2018]暴力書込み掛どちらでもドゥアはサイドと聞いていますが、虚樹dpを分けながらもいいと思いますか?次に題解を見に行きましたが、神様たちは式子化すると言いました.(R x+R y+d_i s(x,y)/2−d_i s’(x,y)(Rux+Ruy+dis(x,y)/2−dis'(x,y)(Rx+Ry+dis(x,y)/2 dily)は、2番目の列挙しかできません.そして一番目の木に、サブツリーの中でポイントの距離が一番大きいかを尋ねます.チャンネルの問題を発見した合併直径は磁気負によらず、辺分治で距離の最大値を探すことを考えています.辺分木は二叉の木で、線分樹のように合併して分木することができます.ガチョウの書き方があまりにも優秀ではないので、空間がちょっと爆発します.
//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
",ans);
Formylove;
}