BZOJ 3611 [Heoi2014]:虚树+树形DP
2016-10-05 01:02
211 查看
时空隧道
今天考试T3正解是虚树…..(看到这个名字我好虚啊….)
现在我们需要处理一棵树上k个点的询问,做一遍树形DP……
复杂度是O(n)的,q个询问,感觉复杂度很爆炸…..>_<……
然后我们可以发现对于每次询问k都不是很大,有用的点貌似不超过2*k个,那么其他点都是来打酱油的?(你来打酱油还徒增复杂度??扔出去斩了QAQ)….
那么问题来了…..肿么拎出来建树??求出所有点的LCA???这就到k^2了,说不定是退化了……再想想?其实并不需要k^2个LCA,想一想就会发现,其实只有k-1个LCA(可以想一想k=3时的情况,你绝对找不出来3个LCA)……那么问题就好办了,复杂度可以降到O(2*k)了……..至于怎么建树?单调栈出场….
我们按照dfs序扫过去,维护一个dep单调不下降的栈,如果当前元素dep小于栈顶,那么就不断把栈顶与前一个元素合并(就是求LCA)……
接下来说DP:
对于求和:
f[i]代表以i为根的子树中询问点的路径总长度,siz[i]代表子树中询问点的个数
转移很简单f[root]+=f[to[i]]+siz[to[i]]*(k-siz[to[i]])*dis[root,to[i]]
(画个图YY一下就懂了)….
对于最大值:
MAX[i]代表子树中最长链(询问点到根)的长度
MAX[root]=max(MAX[root],MAX[to[i]]+dis[root,to[i]])
对于最小值:
MIN[i]代表子树中最短链(询问点到根)的长度
MIN[root]=min(MIN[root],MIN[to[i]]+dis[root,to[i]])
**然而感觉真的建出来有些浪费,在我们维护单调栈的过程中就相当于进行了一次dfs,直接DP就好….然而我只写了暴力重新建树的做法QAQing…..
代码如下:
这个代码很慢,并且有一个数据过不去(QAQ)……今天太晚了,苯宝宝想去睡觉了,明天再改……
by >_< NeighThorn
今天考试T3正解是虚树…..(看到这个名字我好虚啊….)
现在我们需要处理一棵树上k个点的询问,做一遍树形DP……
复杂度是O(n)的,q个询问,感觉复杂度很爆炸…..>_<……
然后我们可以发现对于每次询问k都不是很大,有用的点貌似不超过2*k个,那么其他点都是来打酱油的?(你来打酱油还徒增复杂度??扔出去斩了QAQ)….
那么问题来了…..肿么拎出来建树??求出所有点的LCA???这就到k^2了,说不定是退化了……再想想?其实并不需要k^2个LCA,想一想就会发现,其实只有k-1个LCA(可以想一想k=3时的情况,你绝对找不出来3个LCA)……那么问题就好办了,复杂度可以降到O(2*k)了……..至于怎么建树?单调栈出场….
我们按照dfs序扫过去,维护一个dep单调不下降的栈,如果当前元素dep小于栈顶,那么就不断把栈顶与前一个元素合并(就是求LCA)……
接下来说DP:
对于求和:
f[i]代表以i为根的子树中询问点的路径总长度,siz[i]代表子树中询问点的个数
转移很简单f[root]+=f[to[i]]+siz[to[i]]*(k-siz[to[i]])*dis[root,to[i]]
(画个图YY一下就懂了)….
对于最大值:
MAX[i]代表子树中最长链(询问点到根)的长度
MAX[root]=max(MAX[root],MAX[to[i]]+dis[root,to[i]])
对于最小值:
MIN[i]代表子树中最短链(询问点到根)的长度
MIN[root]=min(MIN[root],MIN[to[i]]+dis[root,to[i]])
**然而感觉真的建出来有些浪费,在我们维护单调栈的过程中就相当于进行了一次dfs,直接DP就好….然而我只写了暴力重新建树的做法QAQing…..
代码如下:
这个代码很慢,并且有一个数据过不去(QAQ)……今天太晚了,苯宝宝想去睡觉了,明天再改……
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> //by NeighThorn using namespace std; const int maxn=1000000+5; int stk[maxn],tail,siz[maxn],M[maxn],is[maxn],k; int n,q,hd[maxn],to[maxn*2],nxt[maxn*2],cnt,dis[maxn],fa[maxn][20+5],G[maxn]; long long sum[maxn],MAX[maxn],MIN[maxn],minans,maxans; inline void add(int x,int y){ to[cnt]=y; nxt[cnt]=hd[x]; hd[x]=cnt++; } inline void dfs(int root,int f){ M[root]=++cnt; for(int i=hd[root];i!=-1;i=nxt[i]) if(to[i]!=f) fa[to[i]][0]=root,dis[to[i]]=dis[root]+1,dfs(to[i],root); } inline void init(void){ for(int j=1;j<=20;j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; } inline int LCA(int x,int y){ if(dis[x]>dis[y]) swap(x,y); int d=dis[y]-dis[x]; for(int i=20;i>=0;i--) if((1<<i)&d) y=fa[y][i]; if(x==y) return x; for(int j=20;j>=0;j--) if(fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j]; return fa[x][0]; } inline void dfs2(int root,int f){ siz[root]=is[root],sum[root]=0,MIN[root]=0x3f3f3f3f,MAX[root]=0; for(int i=hd[root];i!=-1;i=nxt[i]) if(to[i]!=f){ dfs2(to[i],root); siz[root]+=siz[to[i]]; minans=min(minans,MIN[root]+MIN[to[i]]+dis[to[i]]-dis[root]); maxans=max(maxans,MAX[root]+MAX[to[i]]+dis[to[i]]-dis[root]); sum[root]+=sum[to[i]]+siz[to[i]]*(k-siz[to[i]])*(dis[to[i]]-dis[root]); MIN[root]=min(MIN[root],MIN[to[i]]+dis[to[i]]-dis[root]); MAX[root]=max(MAX[root],MAX[to[i]]+dis[to[i]]-dis[root]); } if(is[root]) minans=min(minans,MIN[root]),maxans=max(maxans,MAX[root]),MIN[root]=0; } inline bool cmp(int x,int y){ return M[x]<M[y]; } signed main(void){ freopen("project.in","r",stdin); freopen("project.out","w",stdout); cnt=0;memset(hd,-1,sizeof(hd));scanf("%d",&n); for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x); dis[1]=0,fa[1][0]=1,cnt=0;dfs(1,-1);init(); scanf("%d",&q); while(q--){ scanf("%d",&k); memset(is,0,sizeof(is)); for(int i=1;i<=k;i++) scanf("%d",&G[i]),is[G[i]]=1; sort(G+1,G+k+1,cmp); tail=0;memset(hd,-1,sizeof(hd));cnt=0; for(int i=1;i<=k;i++){ while(tail>1&&dis[LCA(stk[tail],stk[tail-1])]>=dis[LCA(G[i],stk[tail])]){ int a=stk[tail--],b=stk[tail--],c; c=LCA(a,b),stk[++tail]=c; if(a!=c) add(a,c),add(c,a)/*,cout<<a<<" "<<c<<endl*/; if(b!=c) add(b,c),add(c,b)/*,cout<<b<<" "<<c<<endl*/; } stk[++tail]=G[i]; } while(tail>1){ /* int a=stk[tail--],b=stk[tail--],c; c=LCA(a,b),stk[++tail]=c; if(a!=c) add(a,c),add(c,a); if(b!=c) add(b,c),add(c,b); */ add(stk[tail],stk[tail-1]),add(stk[tail-1],stk[tail]),tail--; } minans=0x3f3f3f3f,maxans=0;dfs2(stk[1],-1); printf("%lld %lld %lld\n",sum[stk[1]],minans,maxans); } return 0; }
by >_< NeighThorn
相关文章推荐
- bzoj 3611 [Heoi2014]大工程 虚树 dp
- [Bzoj3611][Heoi2014]大工程(虚树)
- bzoj 3611 [Heoi2014]大工程(虚树+DP)
- [bzoj3611][Heoi2014]大工程
- bzoj3611 [Heoi2014]大工程
- BZOJ 3611 [Heoi2014]大工程 虚树
- Bzoj3611 [Heoi2014]大工程
- bzoj 3611 【heoi2014】大工程 虚树+树形DP
- bzoj3611 [Heoi2014]大工程
- [BZOJ3611] [Heoi2014]大工程(DP + 虚树)
- BZOJ 3611 [Heoi2014]大工程 虚树
- 【BZOJ3611】[Heoi2014]大工程 欧拉序+ST表+单调栈
- BZOJ3611 [Heoi2014]大工程 【虚树】
- bzoj 3611: [Heoi2014]大工程 虚树
- [BZOJ3611][HEOI2014]大工程
- BZOJ 3611 HEOI2014 大工程 倍增LCA+单调栈+树形DP
- BZOJ 3611 HEOI 2014 大工程 LCA单调性
- [bzoj 3611] [heoi 2014] 大工程
- 【bzoj3611】[Heoi2014]大工程 虚树+dp
- [BZOJ3611][Heoi2014]大工程(虚树+树形DP)