bzoj3611: [Heoi2014]大工程
2016-04-11 20:56
344 查看
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3611
题意:中文题。
分析:同消耗战是一类题,询问过多,但是关键节点少,那么我们先建虚树(最大2*max个节点),同消耗战建虚树。然后在树上跑一遍DP即可。O(max*logn)
代码:
#include<map> #include<set> #include<cmath> #include<queue> #include<bitset> #include<math.h> #include<cstdio> #include<vector> #include<string> #include<cstring> #include<iostream> #include<algorithm> #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; const int N=1000100; const int MAX=100000000; const int mod=100000000; const int MOD1=1000000007; const int MOD2=1000000009; const double EPS=0.00000001; typedef long long ll; const ll MOD=998244353; const ll INF=10000000010; typedef double db; typedef unsigned long long ull; int tot,u ,v[2*N],pre[2*N]; void add(int a,int b) { v[tot]=b;pre[tot]=u[a];u[a]=tot++; } int k,in ,de ,fa [22]; void dfs(int a,int b) { k++;in[a]=k; de[a]=de[b]+1;fa[a][0]=b; for (int i=1;i<=20;i++) if (de[a]>1<<i) fa[a][i]=fa[fa[a][i-1]][i-1]; for (int i=u[a];i!=-1;i=pre[i]) if (v[i]!=b) dfs(v[i],a); } ll ans,sum ; int x ,d ,bo ,siz ; int ans_min,ans_max,dismi ,dismx ; int cmp(int a,int b) { return in[a]<in[b]; } int getlca(int a,int b) { if (de[a]<de[b]) { a^=b;b^=a;a^=b; } for (int i=20;i>=0;i--) if (de[a]-(1<<i)>=de[b]) a=fa[a][i]; if (a==b) return a; for (int i=20;i>=0;i--) if (de[a]>1<<i&&fa[a][i]!=fa[b][i]) { a=fa[a][i];b=fa[b][i]; } return fa[a][0]; } void dfs_dp(int a) { siz[a]=bo[a]; sum[a]=0;dismx[a]=0; dismi[a]=bo[a] ? 0:MAX; for (int i=u[a];i!=-1;i=pre[i]) { dfs_dp(v[i]); if (siz[a]) ans_min=min(ans_min,dismi[a]+dismi[v[i]]+de[v[i]]-de[a]); if (siz[a]) ans_max=max(ans_max,dismx[a]+dismx[v[i]]+de[v[i]]-de[a]); ans+=sum[a]*siz[v[i]]+sum[v[i]]*siz[a]+((ll)siz[a]*siz[v[i]])*(de[v[i]]-de[a]); siz[a]+=siz[v[i]]; sum[a]+=sum[v[i]]+(ll)(de[v[i]]-de[a])*siz[v[i]]; dismi[a]=min(dismi[a],dismi[v[i]]+de[v[i]]-de[a]); dismx[a]=max(dismx[a],dismx[v[i]]+de[v[i]]-de[a]); } u[a]=-1; } int main() { int a,b,i,n,m,q,lca; scanf("%d", &n); tot=0;memset(u,-1,sizeof(u)); for (i=1;i<n;i++) { scanf("%d%d", &a, &b); add(a,b);add(b,a); } k=de[1]=0; dfs(1,1); memset(bo,0,sizeof(bo)); tot=0;memset(u,-1,sizeof(u)); scanf("%d", &q); while (q--) { scanf("%d", &m); for (i=1;i<=m;i++) { scanf("%d", &x[i]);bo[x[i]]=1; } sort(x+1,x+m+1,cmp); k=0;d[++k]=1; for (i=1;i<=m;i++) { lca=getlca(x[i],d[k]); while (de[lca]<de[d[k]]) { if (de[lca]>=de[d[k-1]]) { add(lca,d[k]);k--; if (d[k]!=lca) d[++k]=lca; break ; } add(d[k-1],d[k]);k--; } if (d[k]!=x[i]) d[++k]=x[i]; } while (--k) add(d[k],d[k+1]); ans=0;ans_min=MAX;ans_max=0; dfs_dp(1); printf("%lld %d %d\n", ans, ans_min, ans_max); for (i=1;i<=m;i++) bo[x[i]]=0; } return 0; } /* 10 2 1 3 2 4 1 5 2 6 4 7 5 8 6 9 7 10 9 8 2 3 5 3 1 2 3 3 1 2 2 2 5 4 2 10 4 2 5 2 2 6 1 2 6 1 */
相关文章推荐
- 搭建轻量级git server和git web UI
- spring@value注入spel表达式
- 父类与子类的关系
- JAVA大作业 - 五道三星题
- python学习9-语句
- 模拟——Educational Codeforces Round 11——B
- 字符统计(改1)
- linux下管道及重定向
- YTU 3008: 链串的基本运算
- SHTSC2011(SHOI) 双倍回文 一道用Manacher优化的动态维护题
- vector 详细用法 C++
- Centos7 ssh修改默认端口号
- LeetCode Best Time to Buy and Sell Stock III
- Hibernate 检索策略
- 数据结构 --- 线性表学习(php模拟)
- 【html】:html中实现下拉列表
- RabbitMQ入门(一) —— 基本概念
- 山东省第一届ACM省赛 F SDUT 2156 Fairy tale
- YTU 3007: 顺序串的基本运算
- activiti自定义流程之整合(二):使用angular js整合ueditor创建表单