zoukankan      html  css  js  c++  java
  • P1600 [NOIP2016 提高组] 天天爱跑步

    这题被我 3 min 胡出来了的样子。

    考虑,m 对点 $(s_i,t_i)$ 去贡献点 j。

    考虑贡献式: $dep_s+dep_x-2dep_{lca(s,x)}=w_x$。

    如果 $xin [s,lca(s,t)]$,那么 $dep_s-dep_x=w_x,dep_s=dep_x+w_x$,用 $dep_s_$ 去贡献即可。具体我不太会,用了个比较蠢的分块维护桶。

    $ xin[lca(s,t),t]$,那么 $dep_s+dep_x-2*dep_{lca(s,x)}=w_x$,此时 $lca(s,x)=lca(s,t)$,$dep_s-2*dep{lca(s,t)}=w_x-dep_x$,考虑用这东西去贡献下就好。由于 $w_x-dep_x in[-n,n]$,要值域平移。

    注意下空间。时复 $O(nsqrt{n}log n)$。

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <map>
    
    #define ll long long
    
    using namespace std;
    int rd() {
    	int f=1,sum=0; char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    ll lrd() {
    	ll f=1,sum=0; char ch=getchar();
    	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    /* dis=w_x dep_A+dep_x-2*dep_lca=w_x dep_A-2*dep_lca=w_x-dep_x
      分块,块内维护个桶
    */ 
    const int N=(int)(3e5+2),M=410;
    struct edge {
    	int nex,to;
    }e[N<<1];
    int dep[N],fa[N],top[N],son[N],sz[N],id[N],rk[N],tot;
    int head[N],cnt,w[N],ans[N],n,m;
    
    void add_edge(int x,int y) {
    	e[++cnt].nex=head[x]; e[cnt].to=y; head[x]=cnt;
    }
    
    void dfs1(int x,int ff) {
    	dep[x]=dep[ff]+1; fa[x]=ff; sz[x]=1;
    	for(int i=head[x];i;i=e[i].nex) {
    		int y=e[i].to; if(y==ff) continue;
    		dfs1(y,x); sz[x]+=sz[y];
    		if(sz[y]>sz[son[x]]) son[x]=y;
    	}
    }
    
    void dfs2(int x,int tp) {
    	top[x]=tp; id[x]=++tot; rk[tot]=x; 
    	if(son[x]) dfs2(son[x],tp);
    	for(int i=head[x];i;i=e[i].nex) {
    		int y=e[i].to; if(y==fa[x]||y==son[x]) continue;
    		dfs2(y,y);
    	}
    }
    #define K (int)(3e5)
    int L[M],R[M],bid[N],bl,cnt1[M][N<<1],cnt2[M][N<<1];
    void init() {
    	bl=sqrt(1.0*n*1.8); 
    	for(int i=1;i<=n;i++) bid[i]=(i-1)/bl+1;
    	for(int i=1;i<=bid[n];i++) L[i]=(i-1)*bl+1,R[i]=i*bl; R[bid[n]]=n;	
    }	
    
    void upt1(int l,int r,int pos) {
    	if(bid[l]==bid[r]) {
    		for(int i=l;i<=r;i++) if(w[rk[i]]+dep[rk[i]]==pos) ++ans[i];
    	} else {
    		for(int i=l;i<=R[bid[l]];i++) if(w[rk[i]]+dep[rk[i]]==pos) ++ans[i];
    		for(int i=L[bid[r]];i<=r;i++) if(w[rk[i]]+dep[rk[i]]==pos) ++ans[i];
    		for(int i=bid[l]+1;i<bid[r];i++) ++cnt1[i][pos+K];
    	}
    }
    
    void upt2(int l,int r,int pos) {
    	if(bid[l]==bid[r]) {
    		for(int i=l;i<=r;i++) if(w[rk[i]]-dep[rk[i]]==pos) ++ans[i];
    	} else {
    		for(int i=l;i<=R[bid[l]];i++) if(w[rk[i]]-dep[rk[i]]==pos) ++ans[i];
    		for(int i=L[bid[r]];i<=r;i++) if(w[rk[i]]-dep[rk[i]]==pos) ++ans[i];
    		for(int i=bid[l]+1;i<bid[r];i++) ++cnt2[i][pos+K];
    	}
    }
    
    int query(int x) {
    	//cout<<w[x]-dep[x]<<endl;
    	return ans[x]+cnt1[bid[x]][w[rk[x]]+dep[rk[x]]+K]+cnt2[bid[x]][w[rk[x]]-dep[rk[x]]+K];
    }
    
    int LCA(int x,int y) {
    	while(top[x]!=top[y]) {
    		if(dep[top[x]]<dep[top[y]]) swap(x,y);
    		x=fa[top[x]];
    	}
    	return dep[x]<dep[y]?x:y;
    }
    
    // dep_A-dep_x+dis=w_x w_x+dep_x=dep_A+dis
    // dep_A-dep_x=w_x w_x+dep_x=dep_A
    // all_dis-(dep_A-dep_x)=all_dis-dep_A+dep_x=w_x 
    // w_x-dep_x=all_dis-dep_A
    /*
    dep_x+dep_y-2*dep_lca=w_y
    dep_A-dep_x=w_x 
    1. dep_x=w_y+dep_y
    2. dep_x-2*dep_d=w_y-dep_y
    */
    void update1(int x,int y) {
    	int A=x;
    	while(top[x]!=top[y]) {
    		if(dep[top[x]]<dep[top[y]]) swap(x,y);
    		upt1(id[top[x]],id[x],dep[A]);
    		x=fa[top[x]];
    	}
    	if(id[x]>id[y]) swap(x,y);
    	upt1(id[x],id[y],dep[A]);
    }
    
    void update2(int depd,int u,int x,int y) {
    	int A=u;
    	while(top[x]!=top[y]) {
    		if(dep[top[x]]<dep[top[y]]) swap(x,y);
    		upt2(id[top[x]],id[x],dep[A]-2*depd);
    		x=fa[top[x]];
    	}
    	if(id[x]>id[y]) swap(x,y);
    	upt2(id[x],id[y],dep[A]-2*depd);
    }
    
    void pr(int x) {
    	if(x<0) {putchar('-');x=-x;}
    	if(x>9) pr(x/10);
    	putchar(x%10+'0');
    }
    
    int main() {
    	int x,y;
    	n=rd(); m=rd();
    	for(int i=1;i<n;i++) {
    		x=rd(); y=rd();
    		add_edge(x,y); add_edge(y,x);
    	}
    	for(int i=1;i<=n;i++) w[i]=rd();
    	dfs1(1,0); dfs2(1,0);
    	init();
    	while(m--) {
    		x=rd(); y=rd(); int d=LCA(x,y);
    		update1(x,d); update2(dep[d],x,y,d);
    		if(dep[x]-dep[d]==w[d]) --ans[id[d]];
    //		cout<<dep[x]+dep[y]-2*dep[d]<<":
    ";
    	//	 puts("");
    	}
    	for(int i=1;i<=n;i++) pr(query(id[i])),putchar(' ');
    	return 0;
    }
    

      

  • 相关阅读:
    如何才能写一份好的简历?—— 针对程序员的简历。
    【视频】自然框架之分页控件的使用方法(二) 下载、DLL说明和web.config的设置
    【自然框架】QuickPager分页控件,新增一种分页方式——伪URL分页(Postback版)
    【自然框架】QuickPager asp.net 分页控件的Ajax分页方式。
    帮助文档的数据库结构
    自然框架,拆分后的项目关系
    【自然框架】QuickPagerSQL——专门生成分页用的SQL的类库
    【自然框架】QuickPager分页控件的单独的源码 V2.0.4.2。
    【自然框架】n级下拉列表框的原理
    分享一个基于jQuery的锁定表格行列的js脚本。
  • 原文地址:https://www.cnblogs.com/xugangfan/p/15222742.html
Copyright © 2011-2022 走看看