zoukankan      html  css  js  c++  java
  • luogu P4775 [NOI2018]情报中心 线段树合并 虚树 树的直径trick

    LINK:情报中心

    神题!

    写了一下午 写到肚子疼.

    调了一晚上 调到ex

    用的是网上dalao的方法 跑的挺快的.

    对于链的暴力 我不太会kk.

    直接说正解吧:

    分类讨论两种情况:

    1 答案的两条链的LCA不重合.

    2 答案的两条链的LCA重合了.

    会造成这两种讨论是因为我们无法确定如果LCA重合了 固定那条重合的链 另外一个方向上的那两条链是否重合了.

    其他blog里有配图 我就不放了直接口胡.

    前者维护一下两条链第一次重合的地方.

    然后使用线段树合并的时候来统计答案.

    这个地方要注意细节的处理是否恰当.

    后者 利用虚树来针对某个LCA处求答案.

    是在两个支线交汇处使用树的直径的维护两个端点的方法来求出最大值.

    也同时注意细节的处理.

    难写难调.

    code
    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<cctype>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 1000000000000000000ll
    #define inf 100000000000000000ll
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define vep(p,n,i) for(RE int i=p;i<n;++i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define P 1000000007ll
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-10
    #define sq sqrt
    #define S second
    #define F first
    #define mod 1000000007
    #define r(x) t[x].r
    #define l(x) t[x].l
    #define mx1(x) t[x].mx1
    #define mx2(x) t[x].mx2
    #define max(x,y) ((x)<(y)?y:x)
    using namespace std;
    char *fs,*ft,buf[1<<15];
    inline char gc()
    {
    	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
    	RE int x=0,f=1;RE char ch=gc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
    	return x*f;
    }
    inline ll Read()
    {
    	RE ll x=0,f=1;RE char ch=gc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
    	return x*f;
    }
    const int MAXN=50010;
    int n,m,len,T,maxx=50000<<1,id,cnt,rt,top,now;
    int Log[MAXN<<1],dfn[MAXN],q[MAXN<<2],f[MAXN<<1][20],root[MAXN],d[MAXN];
    int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1],e[MAXN<<1],fa[MAXN],vis[MAXN];
    ll dis[MAXN],ans;
    vector<pair<int,ll> >g[MAXN];
    inline void add(int x,int y,int z){ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;}
    struct wy{int l,r;ll mx1,mx2;}t[MAXN*40];
    struct jl{int x,y;ll z;jl(){}jl(int _a,int _b,ll _z){x=_a;y=_b;z=_z;}};
    struct xn
    {
    	jl a,b;ll d;
    	xn(){}
    	xn(jl _a,jl _b,ll _d){a=_a;b=_b;d=_d;}
    	inline ll operator <(xn b){return d<b.d;}
    }w[MAXN];
    vector<jl>s[MAXN];
    inline void dfs(int x,int father)
    {
    	f[++cnt][0]=x;dfn[x]=cnt;d[x]=d[father]+1;fa[x]=father;
    	go(x)if(tn!=fa[x])
    	dis[tn]=dis[x]+e[i],dfs(tn,x),f[++cnt][0]=x;
    }
    inline int cmp(int x,int y){return d[x]<d[y]?x:y;}
    inline int LCA(int x,int y)
    {
    	x=dfn[x];y=dfn[y];
    	if(x>y)swap(x,y);
    	int z=Log[y-x+1];
    	return cmp(f[x][z],f[y-(1<<z)+1][z]);
    }
    inline bool cmp1(int x,int y){return dfn[x]<dfn[y];}
    inline ll dist(int x,int y){return dis[x]+dis[y]-dis[LCA(x,y)]*2;}
    struct solve1//solve 1.
    {
    	inline void pushup(int p)
    	{
    		mx1(p)=max(mx1(l(p)),mx1(r(p)));
    		mx2(p)=max(mx2(l(p)),mx2(r(p)));
    	}
    	inline void insert(int &p,int l,int r,int x,ll c1,ll c2)
    	{
    		if(!p)p=++id,t[p]=t[0];
    		if(l==r){mx1(p)=max(mx1(p),c1);mx2(p)=max(mx2(p),c2);return;}
    		int mid=(l+r)>>1;
    		if(x<=mid)insert(l(p),l,mid,x,c1,c2);
    		else insert(r(p),mid+1,r,x,c1,c2);
    		pushup(p);
    	}
    	inline int merge(int l,int r,int x,int y)
    	{
    		if(!x||!y)return x|y;
    		if(l==r)
    		{
    			mx1(x)=max(mx1(x),mx1(y));
    			mx2(x)=max(mx2(y),mx2(x));
    			return x;
    		}
    		ans=max(ans,mx1(l(x))+mx2(r(y))-dis[now]);
    		ans=max(ans,mx1(l(y))+mx2(r(x))-dis[now]);
    		int mid=(l+r)>>1;
    		l(x)=merge(l,mid,l(x),l(y));
    		r(x)=merge(mid+1,r,r(x),r(y));
    		pushup(x);return x;
    	}
    	inline void change(int &p,int l,int r,int x)
    	{
    		if(!p)return;
    		if(l==r){p=0;return;}
    		int mid=(l+r)>>1;
    		if(x<=mid)change(l(p),l,mid,x);
    		else change(r(p),mid+1,r,x);
    		if(!l(p)&&!r(p))p=0;
    		else pushup(p);
    	}	
    	inline void dfs(int x)
    	{
    		go(x)if(tn!=fa[x])
    		{
    			dfs(tn);
    			change(root[tn],1,n,d[x]);now=x;
    			root[x]=merge(1,n,root[x],root[tn]);
    		}
    		now=x;
    		vep(0,(int)g[x].size(),j)
    		{
    			int r=0;
    			insert(r,1,n,d[g[x][j].F],g[x][j].S,g[x][j].S+dis[g[x][j].F]);
    			root[x]=merge(1,n,root[x],r);
    		}
    	}
    	inline void solve()
    	{
    		dfs(1);
    		rep(1,n,i)root[i]=0,g[i].clear();id=0;
    	}
    }S1;
    struct solve2
    {
    	inline xn calc(jl a,jl b)
    	{
    		ll dd=dist(a.x,b.x)+a.z+b.z;
    		ans=max(ans,dd/2-dis[now]);
    		return xn(a,b,dd);
    	}
    	inline void merge(xn &A,xn &B)
    	{
    		if(A.d==-INF){A=B;B.d=-INF;return;}
    		if(B.d==-INF)return;
    		if(now!=rt)
    		{
    			xn W=max(calc(A.a,B.a),calc(A.a,B.b));
    			W=max(W,calc(A.b,B.a));W=max(W,calc(A.b,B.b));
    			A=max(A,B);A=max(A,W);
    		}
    		B.d=-INF;
    	}
    	inline void calc()
    	{
    		int cc=0;top=0;
    		vep(0,(int)s[rt].size(),j)
    		{
    			q[++top]=s[rt][j].x;q[++top]=s[rt][j].y;
    			jl a=jl(q[top-1],0,s[rt][j].z+dis[q[top]]);
    			jl b=jl(q[top],0,s[rt][j].z+dis[q[top-1]]);
    			xn A=xn(a,a,a.z<<1);xn B=xn(b,b,b.z<<1);
    			merge(w[now=q[top]],A);merge(w[now=q[top-1]],B);
    		}
    		sort(q+1,q+1+top,cmp1);
    		vis[++cc]=rt;q[0]=rt;
    		rep(1,top,i)
    		{
    			if(q[i]==q[i-1])continue;
    			if(cc==1){vis[++cc]=q[i];continue;}
    			int lca=LCA(q[i],vis[cc]);
    			while(cc>1&&d[lca]<=d[vis[cc-1]])
    			{
    				merge(w[now=vis[cc-1]],w[vis[cc]]);
    				--cc;
    			}
    			if(vis[cc]!=lca)merge(w[now=lca],w[vis[cc]]),vis[cc]=lca;
    			vis[++cc]=q[i];
    		}
    		while(cc>1)
    		{
    			merge(w[now=vis[cc-1]],w[vis[cc]]);
    			--cc;
    		}
    		w[rt].d=-INF;
    		//rep(1,top,i)if(w[q[i]].d!=-INF)cout<<"ww"<<endl;
    	}
    	inline void solve()
    	{
    		rep(1,n,i)w[i].d=-INF;
    		rep(1,n,i)if(s[i].size()>1)rt=i,calc();
    		rep(1,n,i)s[i].clear();
    	}
    }S2;
    int main()
    {
    	//freopen("1.in","r",stdin);
    	get(T);mx1(0)=mx2(0)=-INF;
    	rep(2,maxx,i)Log[i]=Log[i>>1]+1;
    	while(T--)
    	{
    		ans=-INF;cnt=0;len=0;
    		rep(1,n,i)lin[i]=0;
    		get(n);
    		rep(2,n,i)
    		{
    			int get(x),get(y),get(z);
    			add(x,y,z);add(y,x,z);
    		}
    		dfs(1,0);
    		rep(1,Log[cnt],j)
    		rep(1,cnt-(1<<j)+1,i)f[i][j]=cmp(f[i][j-1],f[i+(1<<(j-1))][j-1]);
    		//put(dis[4]);
    		get(m);
    		rep(1,m,i)
    		{
    			int get(x),get(y);ll z=Read();
    			if(x==y)continue;
    			int lca=LCA(x,y);ll cc=dist(x,y)-z;
    			if(x!=lca)g[x].pb(mk(lca,cc));
    			if(y!=lca)g[y].pb(mk(lca,cc));
    			s[lca].pb(jl(x,y,cc-z));
    		}
    		S1.solve();
    		S2.solve();
    		//cout<<ans<<' '<<-INF<<' '<<(ans<-INF)<<endl;
    		if(ans<-inf)puts("F");
    		else putl(ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Scan image with TWAIN scanner and insert into Rich Text (R5/Win32)
    软件测试工具汇总
    domino升级602>651
    domino SMTP验证LDAPPOP3的实现
    domino升级602>651>851
    DOMINO中的内置域
    Attaching and importing image files in one click
    传西门子中国运营中近一半业务涉及行贿 沧海
    IT程序员:如何化蛹为蝶? 沧海
    年度个人职业规划秘笈 沧海
  • 原文地址:https://www.cnblogs.com/chdy/p/13387551.html
Copyright © 2011-2022 走看看