[BZOJ3572][HNOI2014]世界树
2016-03-04 21:54
429 查看
这一题调试了蛮久,而且我一写虚树常数就大,是rank1的17倍。
显然是一道虚树题。建出虚树后,先两遍DFS处理出每个虚树上的点的归属,然后考虑虚树每一条边的贡献。
定义sizesize为原树每个子树大小
对于一条边(u,v)(u,v),设xx为原树中uu的儿子vv的祖先。
若bel[u]=bel[v]bel[u]=bel[v],ans[bel[u]]+=size[x]−size[v]ans[bel[u]]+=size[x]-size[v]
否则,在原树u→vu\rightarrow v链上二分一个点midmid,使midmid下面的点属于bel[v]bel[v],上面的属于bel[u]bel[u],ans[bel[u]]+=size[x]−size[mid],ans[bel[v]]+=size[mid]−size[v]ans[bel[u]]+=size[x]-size[mid],ans[bel[v]]+=size[mid]-size[v],最后还要处理不在虚树上的子树,这些子树一定隶属它在虚树上的根的管辖,记一个remrem数组维护这些子树大小即可。
妈的调了3个小时的jg题。我不做工业题谁做工业题。
显然是一道虚树题。建出虚树后,先两遍DFS处理出每个虚树上的点的归属,然后考虑虚树每一条边的贡献。
定义sizesize为原树每个子树大小
对于一条边(u,v)(u,v),设xx为原树中uu的儿子vv的祖先。
若bel[u]=bel[v]bel[u]=bel[v],ans[bel[u]]+=size[x]−size[v]ans[bel[u]]+=size[x]-size[v]
否则,在原树u→vu\rightarrow v链上二分一个点midmid,使midmid下面的点属于bel[v]bel[v],上面的属于bel[u]bel[u],ans[bel[u]]+=size[x]−size[mid],ans[bel[v]]+=size[mid]−size[v]ans[bel[u]]+=size[x]-size[mid],ans[bel[v]]+=size[mid]-size[v],最后还要处理不在虚树上的子树,这些子树一定隶属它在虚树上的根的管辖,记一个remrem数组维护这些子树大小即可。
妈的调了3个小时的jg题。我不做工业题谁做工业题。
#include<ctime> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<cassert> #include<cmath> #include<vector> #include<queue> #include<stack> #include<map> #include<sstream> #include<climits> #define X first #define Y second #define DB double #define lc now<<1 #define rc now<<1|1 #define MP make_pair #define LL long long #define pb push_back #define sqr(_) ((_)*(_)) #define INF 0x3f3f3f3f #define pii pair<int,int> #define pdd pair<DB,DB> #define ull unsigned LL #define DEBUG(...) fprintf(stderr,__VA_ARGS__) using namespace std; template<typename T>void Read(T& x) { x=0;int flag=0,sgn=1;char c; while(c=getchar()) { if(c=='-')sgn=-1; else if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1; else if(flag)break; } x*=sgn; } const int MAXN=601000; int n,m,k,h[MAXN],ans[MAXN],pa[MAXN],iskey[MAXN]; int A[MAXN],size_a=0; int dep[MAXN],fa[MAXN][20],bel[MAXN],dfn[MAXN],size[MAXN],rem[MAXN]; pii clo[MAXN]; struct Tree{ int e,dfs_clock,first[MAXN],next[MAXN],to[MAXN]; void init() { memset(first,0,sizeof(first)); e=dfs_clock=0; } void add(int u,int v) {//if you judge i==0 instead of i==-1 ++e first ++e;next[e]=first[u];first[u]=e;to[e]=v; ++e;next[e]=first[v];first[v]=e;to[e]=u; } void dfs(int u,int f) { if(u==1)dep[u]=1; else dep[u]=dep[f]+1; fa[u][0]=f; size[u]=1; dfn[u]=++dfs_clock; for(int i=1;i<20;i++) fa[u][i]=fa[fa[u][i-1]][i-1]; for(int i=first[u];i;i=next[i]) { int v=to[i]; if(v==f)continue; dfs(v,u); size[u]+=size[v]; } } int LCA(int x,int y) { if(dep[x]<dep[y])swap(x,y); if(!y)return y; for(int i=18;i>=0;i--) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i]; if(x==y)return x; for(int i=18;i>=0;i--) if(fa[x][i]&&fa[y][i]&&fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i]; return fa[x][0]; } }ori,vit; int dis(int u,int v) { return dep[u]+dep[v]-2*dep[ori.LCA(u,v)]; } void dfs1(int u,int f) { rem[u]=size[u]; for(int i=vit.first[u];i;i=vit.next[i]) { int v=vit.to[i]; if(v==f)continue; if(u!=0) { int D=dis(u,v); if(clo[v].X>clo[u].X+D)//> instead of < clo[v].Y=clo[u].Y, clo[v].X=clo[u].X+D; else if(clo[v].X==clo[u].X+D)//NO judging if(clo[u].Y<clo[v].Y) clo[v].Y=clo[u].Y; } dfs1(v,u); } bel[u]=clo[u].Y; } void dfs2(int u,int f) { for(int i=vit.first[u];i;i=vit.next[i]) { int v=vit.to[i]; if(f==v)continue; dfs2(v,u); int D=dis(u,v); if(clo[u].X>clo[v].X+D) { clo[u].X=clo[v].X+D; clo[u].Y=clo[v].Y; } else if(clo[u].X==clo[v].X+D&&clo[v].Y<clo[u].Y) { clo[u].X=clo[v].X+D; clo[u].Y=clo[v].Y; } } } void fuck(int u,int v)//algorithm error { int mid=v,a=v; for(int i=18;i>=0;i--) if(fa[a][i]&&dep[fa[a][i]]>dep[u]) a=fa[a][i]; rem[u]-=size[a]; if(bel[u]==bel[v]) { ans[bel[u]]+=size[a]-size[v]; return; } for(int i=18;i>=0;i--) if(fa[mid][i]&&dis(fa[mid][i],bel[u])>dis(fa[mid][i],bel[v])) mid=fa[mid][i]; if(dis(fa[mid][0],bel[u])==dis(fa[mid][0],bel[v])) if(bel[u]>bel[v]) mid=fa[mid][0]; ans[bel[v]]+=size[mid]-size[v]; ans[bel[u]]+=size[a]-size[mid]; } void work(int u,int f) { if(f==0) ans[bel[u]]+=n-size[u]; for(int i=vit.first[u];i;i=vit.next[i]) { int v=vit.to[i]; if(v==f)continue; if(u!=0) fuck(u,v); work(v,u); } ans[bel[u]]+=rem[u]; } int top,st[MAXN]; bool cmp(const int& x,const int& y) { return dfn[x]<dfn[y]; } void solve() { size_a=0; vit.init(); top=0; st[++top]=0; sort(h+1,h+k+1,cmp); for(int i=1;i<=k;i++) { int x=ori.LCA(st[top],h[i]); A[size_a++]=x; A[size_a++]=h[i]; for(;dep[st[top]]>dep[x];--top) if(dep[st[top-1]]<=dep[x]) pa[st[top]]=x; if(x!=st[top]) { pa[x]=st[top]; st[++top]=x; } pa[st[++top]=h[i]]=x; } sort(A,A+size_a); size_a=unique(A,A+size_a)-A; for(int i=0;i<size_a;i++) vit.first[A[i]]=0; for(int i=0;i<size_a;i++) { if(A[i]==0)continue; //DEBUG("%d %d\n",A[i],pa[A[i]]); vit.add(A[i],pa[A[i]]); } clo[0].X=INF; for(int i=0;i<size_a;i++) if(iskey[A[i]]) clo[A[i]].X=0,clo[A[i]].Y=A[i]; else clo[A[i]].X=INF; dfs2(0,0);//dfs2 first! dfs1(0,0); work(0,-1); } int tmp[MAXN]; int main() { #ifndef ONLINE_JUDGE freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); #endif ori.init(); Read(n); for(int i=1;i<n;i++) { int a,b; Read(a);Read(b); ori.add(a,b); } ori.dfs(1,0); Read(m); for(int i=1;i<=m;i++) { Read(k); for(int j=1;j<=k;j++) Read(h[j]),iskey[h[j]]=1; memcpy(tmp,h,sizeof(int)*(k+1)); solve(); for(int j=1;j<=k;j++) { printf("%d ",ans[tmp[j]]==0?1:ans[tmp[j]]); iskey[tmp[j]]=ans[tmp[j]]=0; } puts(""); } }
相关文章推荐
- Linux下设置程序自启动
- Animation Animate Armture三个动画的使用
- 算法导论3.1-1
- Oracle X2-2 一体机Solaris 平台最佳实践 (文档 ID 2009867.1)
- 每天一个linux命令(53):route命令 【转】
- 针对数据泵导出 (expdp) 和导入 (impdp)工具性能降低问题的检查表 (文档 ID 1549185.1)
- 【GDKOI2016】QT与泰剧Code&Details
- Windows下查看局域网内某台计算机的MAC地址
- Hadoop 2.x高可用配置
- ACM输入输出格式记录
- 红黑树和B树应用场景总结
- MFC 非模态对话框一闪而过
- js获取url?后的参数
- codevs 1455 路径
- 产品经理必备软件——Axure使用详解(3)
- java观察者模式(一)
- 视频采集处理之YUV数据格式
- 20145328 《Java程序设计》第0周学习总结
- 从AppStore获取一个iOS App的版本信息
- 每天一个linux命令(51):lsof命令 【转】