zoukankan      html  css  js  c++  java
  • bzoj3572: [Hnoi2014]世界树

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3572

    思路:注意到m[1]+m[2]+…+m[q]<=300000

    上虚树Dp。

    先DP出虚树上每个点被哪个点管辖,记为bel[i]。

    这个从上到下更新一次答案,在从下到上更新一次答案即可。

    对于最终答案,我们遍历一遍虚树,把虚树每条边对应的点划分好即可


    然后我们考虑虚树的一条边(a,b)

    记x为既是a的儿子又是b的祖先的点,siz[a]表示a点的子树大小

    1.如果bel[a]==bel[b]那么这条边所对应的一堆实际的点也应该归bel[a]管辖

    那么f[bel[a]]+=siz[x]-siz[b]

    2.如果bel[a]!=bel[b]那么这条边(在原树上是一条路径)中一定有一个分界点mid

    使得mid及以下的点归bel[b]管辖,mid以上的点归bel[a]管辖

    倍增找出mid即可

    那么f[bel[a]]+=siz[x]-siz[mid],f[bel[b]]+=siz[mid]-siz[b]


    最后要处理的是完全没有在虚树上出现的子树,这些子树肯定被控制它们的根的点所控制

    我们记录一个rem[i]表示i的子树现在还有多少个点没被统计答案,初值为siz[i]

    处理了一条边(a,b)后,那么x的子树就在处理虚树时已经被我们处理完了,记得减去,rem[a]-=siz[x]

    最后把这些多余的点加回去即可,f[bel[a]]+=rem[a]

    然后有一个细节,记得把虚树的根的rem设为整个树的大小,而不是它的siz,因为那样会使我们漏掉原来的根的其他子树


    实现的时候注意细节(各种乱七八糟的问题)....

    不知道为什么这么慢....(看来是写丑了)


    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int maxn=300010,maxm=600010,maxk=22;
    using namespace std;
    int n,m,fa[maxn][maxk],dep[maxn],siz[maxn],dfn[maxn],tim,f[maxn],cnt,poi[maxn],bel[maxn],stk[maxn],top,ordc,ord[maxn],seq[maxn],rem[maxn];
    bool bo[maxn];char ch;
    bool cmp(int a,int b){return dfn[a]<dfn[b];}
    void read(int &x){
    	for (ch=getchar();!isdigit(ch);ch=getchar());
    	for (x=0;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    }
    int lca(int a,int b){
    	if (dep[a]<dep[b]) swap(a,b);
    	for (int h=dep[a]-dep[b],i=19;i>=0;i--) if (h>=(1<<i)) h-=(1<<i),a=fa[a][i];
    	if (a==b) return a;
    	for (int i=19;i>=0;i--) if (fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i];
    	return fa[a][0];
    }
    int getd(int a,int b){return dep[a]+dep[b]-(dep[lca(a,b)]<<1);}
    
    struct Tgraph{
    	int pre[maxm],now[maxn],son[maxm],tot;
    	void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;}
    	void dfs1(int x){
    		siz[x]=1,dfn[x]=++tim;
    		for (int i=1;i<=19;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    		for (int y=now[x];y;y=pre[y]) if (son[y]!=fa[x][0])
    			dep[son[y]]=dep[x]+1,fa[son[y]][0]=x,dfs1(son[y]),siz[x]+=siz[son[y]];
    	}
    	void dfs2(int x){//找子树中最近的关键点
    		ord[++ordc]=x,rem[x]=siz[x];
    		for (int y=now[x];y;y=pre[y]){
    			int v=son[y];dfs2(v);
    			if (!bel[v]) continue;
    			int t1=getd(x,bel[v]),t2=getd(x,bel[x]);
    			if (!bel[x]||t1<t2||(t1==t2&&bel[v]<bel[x])) bel[x]=bel[v];
    		}
    	}
    	void dfs3(int x){//找上面最近的关键点
    		for (int y=now[x];y;y=pre[y]){
    			int v=son[y],t1=getd(v,bel[x]),t2=getd(bel[v],v);
    			if (!bel[v]||t1<t2||(t1==t2&&bel[x]<bel[v])) bel[v]=bel[x];
    			dfs3(v);
    		}
    	}
    	void solve(int a,int b){//处理虚边a->b
    		int x=b,mid=b;
    		for (int i=19;i>=0;i--) if (dep[fa[x][i]]>dep[a]) x=fa[x][i];
    		rem[a]-=siz[x];
    		if (bel[a]==bel[b]){f[bel[a]]+=siz[x]-siz[b];return;}
    		for (int i=19;i>=0;i--){
    			int nxt=fa[mid][i];
    			if (dep[nxt]<=dep[a]) continue;
    			int t1=getd(bel[a],nxt),t2=getd(bel[b],nxt);
    			if (t2<t1||(t1==t2&&bel[b]<bel[a])) mid=nxt;
    		}
    		f[bel[a]]+=siz[x]-siz[mid],f[bel[b]]+=siz[mid]-siz[b];
    	}
    	void getans(){
    		for (int i=1;i<=ordc;i++) for (int y=now[ord[i]];y;y=pre[y]) solve(ord[i],son[y]);
    		for (int i=1;i<=ordc;i++) f[bel[ord[i]]]+=rem[ord[i]];
    		for (int i=1;i<=cnt;i++) printf("%d ",f[seq[i]]);puts("");
    	}
    }g1,g2;
    
    void work(){
    	stk[top=1]=poi[1];
    	for (int i=2;i<=cnt;i++){
    		int u=lca(poi[i],stk[top]);
    		while (dfn[stk[top]]>dfn[u]){
    			if (dfn[stk[top-1]]<=dfn[u]){
    				g2.add(u,stk[top]);
    				if (u!=stk[--top]) stk[++top]=u;
    				break;
    			}
    			g2.add(stk[top-1],stk[top]),top--;
    		}
    		stk[++top]=poi[i];
    	}
    	while (top>1) g2.add(stk[top-1],stk[top]),top--;
    	g2.dfs2(stk[1]),g2.dfs3(stk[1]),rem[stk[1]]=siz[1],g2.getans();
    	for (int i=1;i<=ordc;i++){int p=ord[i];f[p]=g2.now[p]=rem[p]=bel[p]=0;}
    	g2.tot=ordc=0;
    }
    
    int main(){
    	read(n);
    	for (int i=1,a,b;i<n;i++) read(a),read(b),g1.add(a,b),g1.add(b,a);
    	g1.dfs1(1),read(m);
    	while (m--){
    		read(cnt);
    		for (int i=1;i<=cnt;i++) read(poi[i]),seq[i]=poi[i],bo[poi[i]]=1,bel[poi[i]]=poi[i];
    		sort(poi+1,poi+1+cnt,cmp),work();
    	}
    	return 0;
    }
    
    /*
    10
    2 1
    3 2
    4 3
    5 4
    6 1
    7 3
    8 3
    9 4
    10 1
    5
    2
    6 1
    5
    2 7 3 6 9
    1
    8
    4
    8 7 10 3
    5
    2 9 3 5 8
    */


  • 相关阅读:
    不可小视视图对效率的影响力
    Maximum Margin Planning
    PhysicsBased Boiling Simulation

    Learning Behavior Styles with Inverse Reinforcement Learning
    Simulating Biped Behaviors from Human Motion Data
    Nearoptimal Character Animation with Continuous Control
    Apprenticeship Learning via Inverse Reinforcement Learning
    回报函数学习的学徒学习综述
    Enabling Realtime Physics Simulation in Future Interactive Entertainment
  • 原文地址:https://www.cnblogs.com/thythy/p/5493491.html
Copyright © 2011-2022 走看看