zoukankan      html  css  js  c++  java
  • 天天爱跑步

    题目链接:P1600 天天爱跑步

    暴力程序(25pts) 复杂度(O(n^2))

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=3e5+10;
    int n,m,ans[maxn];
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    int beg[maxn],nex[maxn<<1],to[maxn<<1],e;
    inline void add(int x,int y){
    	e++;nex[e]=beg[x];
    	beg[x]=e;to[e]=y;
    }
    int dep[maxn],f[maxn][20]; 
    inline void dfs(int x,int fa){
    	dep[x]=dep[fa]+1;
    	f[x][0]=fa;
    	for(int i=1;i<=19;i++)
    		f[x][i]=f[f[x][i-1]][i-1];
    	for(int i=beg[x];i;i=nex[i]){
    		int t=to[i];
    		if(t==fa)continue;
    		dfs(t,x);
    	}
    }
    inline int lca(int x,int y){
    	if(dep[x]<dep[y])swap(x,y);
    	for(int i=19;i>=0;i--)
    		if(dep[f[x][i]]>=dep[y])x=f[x][i];
    	if(x==y)return x;
    	for(int i=19;i>=0;i--)
    		if(f[x][i]!=f[y][i]){
    			x=f[x][i];
    			y=f[y][i];
    		}
    	return f[x][0];
    }
    int s[maxn],t[maxn],anc[maxn],w[maxn];
    int main(){
    	n=read(),m=read();
    	int x,y;
    	for(int i=1;i<n;i++){
    		x=read(),y=read();
    		add(x,y),add(y,x);
    	}
    	dfs(1,0);
    	for(int i=1;i<=n;i++)
    		w[i]=read();
    	for(int i=1;i<=m;i++){
    		s[i]=read(),t[i]=read();
    		anc[i]=lca(s[i],t[i]);
    		x=0,y=dep[s[i]]+dep[t[i]]-2*dep[anc[i]];
    		for(int j=s[i];j!=anc[i];j=f[j][0],x++)
    			if(w[j]==x)ans[j]++;
    		for(int j=t[i];j!=anc[i];j=f[j][0],y--)
    			if(w[j]==y)ans[j]++;
    		if(w[anc[i]]==dep[s[i]]-dep[anc[i]])
    			ans[anc[i]]++;
    	}
    	for(int i=1;i<=n;i++)
    		printf("%d ",ans[i]);
    	puts("");
    	return 0;
    }
    

    考虑如何优化。

    考虑一个点(x)在路径(s->t)上,则分两种情况讨论:

    1.若(x)(s->lca)上,则需满足条件(dep[s]-dep[x]=w[x])时才能观察到,即(dep[x]+w[x]=dep[s])

    2.若(x)(lca->t)上,则需满足条件(dis_{s,t}-(dep[t]-dep[x])=w[x])时才能观察到,即(dis_{s,t}-dep[t]=w[x]-dep[x])

    注意:若(dep[lca]+w[lca]=dep[s])(lca)会被计算两次,需减去一次。

    由于等式两边无直接联系,考虑使用线段树合并。

    注意:在(dep[x]<dep[lca])时,(x)不在(s->t)上,故应在(f[lca])处消除这一条边的贡献,其思想类似于树上差分。

    完整代码如下: 复杂度(O(nlog n))

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=3e5+10;
    int n,m,ans[maxn];
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    	return x*f;
    }
    int beg[maxn],nex[maxn<<1],to[maxn<<1],e;
    inline void add(int x,int y){
    	e++;nex[e]=beg[x];
    	beg[x]=e;to[e]=y;
    }
    int dep[maxn],f[maxn][20]; 
    inline void dfs(int x,int fa){
    	dep[x]=dep[fa]+1;
    	f[x][0]=fa;
    	for(int i=1;i<=19;i++)
    		f[x][i]=f[f[x][i-1]][i-1];
    	for(int i=beg[x];i;i=nex[i]){
    		int t=to[i];
    		if(t==fa)continue;
    		dfs(t,x);
    	}
    }
    inline int lca(int x,int y){
    	if(dep[x]<dep[y])swap(x,y);
    	for(int i=19;i>=0;i--)
    		if(dep[f[x][i]]>=dep[y])x=f[x][i];
    	if(x==y)return x;
    	for(int i=19;i>=0;i--)
    		if(f[x][i]!=f[y][i]){
    			x=f[x][i];
    			y=f[y][i];
    		}
    	return f[x][0];
    }
    /*
    if x on s->lca dep[x]+w[x]=dep[s]
    if x on lca->t dis-(dep[t]-dep[x])=w[x]
    	=>dis-dep[t]+n=w[x]-dep[x]+n
    */
    struct node{
    	int sv,tv,l,r;
    }tr[maxn*50];
    int cnt,rt[maxn];
    inline int update_s(int h,int l,int r,int x,int y){
    	if(!h)h=++cnt;
    	tr[h].sv+=y;
    	if(l==r)return h;
    	int mid=(l+r)>>1;
    	if(mid>=x)tr[h].l=update_s(tr[h].l,l,mid,x,y);
    	else tr[h].r=update_s(tr[h].r,mid+1,r,x,y);
    	return h;
    }
    inline int update_t(int h,int l,int r,int x,int y){
    	if(!h)h=++cnt;
    	tr[h].tv+=y;
    	if(l==r)return h;
    	int mid=(l+r)>>1;
    	if(mid>=x)tr[h].l=update_t(tr[h].l,l,mid,x,y);
    	else tr[h].r=update_t(tr[h].r,mid+1,r,x,y);
    	return h;
    }
    int anc[maxn],dis[maxn],w[maxn];
    inline int merge(int s,int t,int l,int r){
    	if(!s||!t)return s+t;
    	if(l==r){
    		tr[s].sv+=tr[t].sv;
    		tr[s].tv+=tr[t].tv;
    		return s;
    	}
    	int mid=(l+r)>>1;
    	tr[s].l=merge(tr[s].l,tr[t].l,l,mid);
    	tr[s].r=merge(tr[s].r,tr[t].r,mid+1,r);
    	return s;
    }
    inline int query_s(int h,int l,int r,int x){
    	if(!h)return 0;
    	if(l==r)return tr[h].sv;
    	int mid=(l+r)>>1;
    	if(mid>=x)return query_s(tr[h].l,l,mid,x);
    	else return query_s(tr[h].r,mid+1,r,x);
    }
    inline int query_t(int h,int l,int r,int x){
    	if(!h)return 0;
    	if(l==r)return tr[h].tv;
    	int mid=(l+r)>>1;
    	if(mid>=x)return query_t(tr[h].l,l,mid,x);
    	else return query_t(tr[h].r,mid+1,r,x);
    }
    inline void solve(int x,int fa){
    	for(int i=beg[x];i;i=nex[i]){
    		int t=to[i];
    		if(t==fa)continue;
    		solve(t,x);
    		rt[x]=merge(rt[x],rt[t],0,2*n);
    	}
    	ans[x]+=query_s(rt[x],0,2*n,dep[x]+w[x]);
    	ans[x]+=query_t(rt[x],0,2*n,w[x]-dep[x]+n);
    }
    int s[maxn],t[maxn];
    int main(){
    	n=read(),m=read();
    	int x,y;
    	for(int i=1;i<n;i++){
    		x=read(),y=read();
    		add(x,y),add(y,x);
    	}
    	dfs(1,0);
    	for(int i=1;i<=n;i++)
    		w[i]=read();
    	for(int i=1;i<=m;i++){
    		s[i]=read(),t[i]=read();
    		anc[i]=lca(s[i],t[i]);
    		dis[i]=dep[s[i]]+dep[t[i]]-2*dep[anc[i]];
    		if(w[anc[i]]==dep[s[i]]-dep[anc[i]])ans[anc[i]]--;
    		rt[s[i]]=update_s(rt[s[i]],0,2*n,dep[s[i]],1);
    		rt[t[i]]=update_t(rt[t[i]],0,2*n,dis[i]-dep[t[i]]+n,1);
    		rt[f[anc[i]][0]]=update_s(rt[f[anc[i]][0]],0,2*n,dep[s[i]],-1);
    		rt[f[anc[i]][0]]=update_t(rt[f[anc[i]][0]],0,2*n,dis[i]-dep[t[i]]+n,-1);
    	}
    	solve(1,0);
    	for(int i=1;i<=n;i++)
    		printf("%d ",ans[i]);
    	puts("");
    	return 0;
    }
    
    

    深深地感到自己的弱小。

  • 相关阅读:
    asp.net textbox 控件如何清除缓存
    extjs Accordion 怎样把展开符号:加号(+)放在左边?
    ORACLE 调试输出,字符串执行函数
    Oracle中table函数的应用
    Oracle LAST_DAY(d)
    Oracle 管道化表函数(Pipelined Table)[转载]
    ext中fieldLabel文本太宽的问题,以及Panel居中显示
    什么是泛型(C#)
    设置Ext tab的宽度自动适应
    js选择日期即时把两个日期相差天数显示出来?
  • 原文地址:https://www.cnblogs.com/syzf2222/p/13746825.html
Copyright © 2011-2022 走看看