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

    传送门

    很容易看出是虚树吧,难点在于统计答案
    可以考虑将虚树上的点预处理出来是由哪些关键点控制的
    可以两次dfs初步处理一下(考虑下对上的影响和上对下的影响,但是兄弟节点之间的关系更新不到,需要在统计答案时更新一下)
    然后考虑统计答案
    考虑每个点(u)不在虚树中的儿子(v),记它为size[v],size[v]初始是原树上的size
    对于虚树上((u,v))这条边,倍增求出((u,v))这条路径上的离(u)最近的点(原树上的)
    减去这些点的size得到的就是由控制(u)的点的贡献
    然后考虑虚边的答案,显然有一条分界的边或者点,找出分界的边或点就能统计了
    细节确实有点麻烦,我写的代码已经有点看不得了
    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    void read(int &x) {
    	char ch; bool ok;
    	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=5e5+10,inf=1e9;
    int n,q,dep[maxn],id[maxn],tmp,f[maxn][20],d[maxn],st[maxn];
    int top,sz[maxn],size[maxn],ans[maxn],vis[maxn];
    int con[maxn],ct[maxn];
    struct oo{
    	int pre[maxn*2],nxt[maxn*2],h[maxn],cnt,v[maxn*2];
    	void add(int x,int y,int z)
    	{
    		pre[++cnt]=y,nxt[cnt]=h[x],h[x]=cnt,v[cnt]=z;
    		pre[++cnt]=x,nxt[cnt]=h[y],h[y]=cnt,v[cnt]=z;
    	}
    }a,b;
    void dfs(int x)
    {
    	id[x]=++tmp,sz[x]=1;
    	for(rg int i=1;i<20;i++)
    	{
    		if(dep[x]<(1<<i))break;
    		f[x][i]=f[f[x][i-1]][i-1];
    	}
    	for(rg int i=a.h[x];i;i=a.nxt[i])
    		if(a.pre[i]!=f[x][0])
    		{
    			f[a.pre[i]][0]=x,dep[a.pre[i]]=dep[x]+1;
    			dfs(a.pre[i]),sz[x]+=sz[a.pre[i]];
    		}
    }
    int lca(int x,int y)
    {
    	if(dep[x]>dep[y])swap(x,y);
    	int poor=dep[y]-dep[x];
    	for(rg int i=19;i>=0;i--)if(poor&(1<<i))y=f[y][i];
    	if(x==y)return x;
    	for(rg int i=19;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    	return x==y?x:f[x][0];
    }
    bool cmp(int a,int b){return id[a]<id[b];}
    void dfs1(int x,int fa)
    {
    	if(vis[x])ct[x]=0,con[x]=x;
    	for(rg int i=b.h[x];i;i=b.nxt[i])
    		if(b.pre[i]!=fa)
    		{
    			if(ct[x]+b.v[i]<ct[b.pre[i]]||(ct[x]+b.v[i]==ct[b.pre[i]]&&con[x]<con[b.pre[i]]))
    				ct[b.pre[i]]=ct[x]+b.v[i],con[b.pre[i]]=con[x];
    			dfs1(b.pre[i],x);
    		}
    }
    void dfs2(int x,int fa)
    {
    	for(rg int i=b.h[x];i;i=b.nxt[i])
    		if(b.pre[i]!=fa)
    		{
    			dfs2(b.pre[i],x);
    			if(ct[b.pre[i]]+b.v[i]<ct[x]||(ct[b.pre[i]]+b.v[i]==ct[x]&&con[b.pre[i]]<con[x]))
    				ct[x]=ct[b.pre[i]]+b.v[i],con[x]=con[b.pre[i]];
    		}
    }
    int jump(int x,int y)
    {
    	for(rg int i=19;i>=0;i--)if(y&(1<<i))x=f[x][i];
    	return x;
    }
    void prepare(int x,int fa)
    {
    	size[x]=sz[x],con[x]=ct[x]=inf;
    	for(rg int i=b.h[x];i;i=b.nxt[i])
    		if(b.pre[i]!=fa)prepare(b.pre[i],x);
    }
    void solve(int x,int fa)
    {
    	for(rg int i=b.h[x];i;i=b.nxt[i])
    		if(b.pre[i]!=fa)
    		{
    			int z=jump(b.pre[i],b.v[i]-1);
    			size[x]-=sz[z];
    		}
    	ans[vis[con[x]]]+=size[x];
    	for(rg int i=b.h[x];i;i=b.nxt[i])
    		if(b.pre[i]!=fa)
    		{
    			if(ct[x]+b.v[i]<ct[b.pre[i]]||(ct[x]+b.v[i]==ct[b.pre[i]]&&con[x]<con[b.pre[i]]))
    				ct[b.pre[i]]=ct[x]+b.v[i],con[b.pre[i]]=con[x];
    			int c=b.pre[i],d=b.v[i],now=ct[x]+ct[c]+d;
    			if(d==1){solve(b.pre[i],x);continue;}
    			if(now&1)
    			{
    				now=now/2-ct[c];int v=jump(c,now);
    				ans[vis[con[c]]]+=sz[v]-sz[c];
    				int z=jump(c,d-1);ans[vis[con[x]]]+=sz[z]-sz[v]; 
    			}
    			else 
    			{
    				now=now/2-ct[c];int v=jump(c,now);
    				if(v==x)
    				{
    					int z=jump(c,d-1);
    					ans[vis[con[c]]]+=sz[z]-sz[c];
    					solve(b.pre[i],x);
    					continue;
    				}
    				int z=jump(c,d-1),p=jump(c,now-1);
    				if(con[c]<con[x])ans[vis[con[c]]]+=sz[v]-sz[c],ans[vis[con[x]]]+=sz[z]-sz[v];
    				else ans[vis[con[c]]]+=sz[p]-sz[c],ans[vis[con[x]]]+=sz[z]-sz[p];
    			}
    			solve(b.pre[i],x);
    		}
    }
    int main()
    {
    	read(n);
    	for(rg int i=1,x,y;i<n;i++)read(x),read(y),a.add(x,y,0);
    	dfs(1),read(q);
    	for(rg int i=1,m;i<=q;i++)
    	{
    		read(m);st[++top]=1,b.cnt=0;memset(b.h,0,sizeof b.h);
    		for(rg int j=1;j<=m;j++)read(d[j]),vis[d[j]]=j;sort(d+1,d+m+1,cmp);
    		for(rg int j=1;j<=m;j++)
    		{
    			int w=0,e=0;
    			while(top&&lca(st[top],d[j])!=st[top])
    			{
    				if(w)b.add(w,st[top],dep[w]-dep[st[top]]);
    				w=st[top],top--;
    			}
    			if(w)e=lca(w,d[j]),b.add(w,e,dep[w]-dep[e]);
    			if(e&&st[top]!=e)st[++top]=e;
    			st[++top]=d[j];
    		}
    		while(top>1)
    		{
    			if(st[top]!=st[top-1])b.add(st[top],st[top-1],dep[st[top]]-dep[st[top-1]]);
    			top--;
    		}
    		prepare(1,0),dfs1(1,0),dfs2(1,0),solve(1,0);
    		for(rg int j=1;j<=m;j++)printf("%d ",ans[j]);printf("
    ");
    		for(rg int j=1;j<=m;j++)vis[d[j]]=ans[j]=0;
    	}
    }
    
  • 相关阅读:
    thinkphp计划任务使用cronRun-Thinkphp3.1版
    AJAX 跨域请求
    可以做外汇交易接口的网站
    thinkphp 定时执行php文件 php自动执行php文件
    关于major、minor的解释
    Codeforces Round #370 (Div. 2) A B C 水 模拟 贪心
    2016 ACM/ICPC Asia Regional Dalian Online 1006 /HDU 5873
    Codeforces Round #280 (Div. 2) A B C 暴力 水 贪心
    codevs 1299 线段树 区间更新查询
    Codeforces Round #260 (Div. 2) A B C 水 找规律(大数对小数取模) dp
  • 原文地址:https://www.cnblogs.com/lcxer/p/10476803.html
Copyright © 2011-2022 走看看