辺分治

178855 ワード

記事の目次
  • bzoj 2870.最長道路tree
  • uoj 347.【WC 2018】チャネル
  • [CTSC2018]暴力書き込み
  • -------3.14 up----------
    今日書きながら分治した時、このブログのトップ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; }