• Codechef Union on Tree


    Codechef Union on Tree

    https://www.codechef.com/problems/BTREE

    简要题意:

    • 给你一棵树,(Q)次询问,每次给出一个点集和每个点的(r_i),每个点可以覆盖距离小于等于(r_i)的点。
    • 问有多少点会被覆盖。

    分析:

    • 建出虚树,然后我们做两边(dp​)把所有点的(r_i​)更新成从这个点能覆盖的最远距离或从其他点出来经过这个点后能够覆盖的最远距离。
    • 这样做的好处是对于一条边((x,y)),一定存在一个点(z),使得(y)更新(z)(x)优。
    • 于是可以计算答案,令(F(x,d))为和(x)距离小于等于(d)的点数。
    • 答案等于(sumlimits_iF(i,r_i)-sumlimits_{x,y,pin x,pin y}1)。 前面那个直接求就行了。
    • 后面那个相当于找到这个(z),设(x)(y)的祖先,有多个点在(z)上边被(y)包含,有多少点在(z)下边被(x)包含。
    • 由于(r_x-(dep_z-dep_x)=r_y-(dep_y-dep_z)),可以确定(z)的位置,同时可以发现所求的点向上下延伸的长度是相等的,于是相当于求(F(z,r_x-(dep_z-dep_x)))
    • (F)可以用动态点分治。
    • 还有一个问题,可能不存在(z)这个点,可能在边上,我们一开始把边也当成点就好了。

    代码:

     #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <iostream>
    #include <vector>
    using namespace std;
    #define N 100050
    char buf[100000],*p1,*p2;
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    inline int rd() {int x=0;char c=nc(); while(c<48)c=nc();while(c>47)x=((x+(x<<2))<<1)+(c^48),c=nc(); return x;}
    #define db(x) cerr<<#x<<" = "<<x<<endl
    int head[N],to[N<<1],nxt[N<<1],cnt,n,m,ff[N],lm;
    int siz[N],fk[N],tot,root,dep[N],fa[N][20],dis[N][20],used[N],ans;
    int sz[N],son[N],d[N],f[N],top[N],dfn[N],idf[N];
    int p[N],r[N],S[N],tp,vis[N];
    vector<int>V[N][2];
    inline void add(int u,int v) {to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;}
    void gr(int x,int y) {
    	int i; siz[x]=1; fk[x]=0;
    	for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!used[to[i]]) {
    		gr(to[i],x); siz[x]+=siz[to[i]]; fk[x]=max(fk[x],siz[to[i]]);
    	}
    	fk[x]=max(fk[x],tot-siz[x]); if(fk[x]<fk[root]) root=x;
    }
    void gd(int x,int y,int rt,int d) {
    	sz[rt]+=(x<=n); V[rt][0][d]+=(x<=n); V[rt][1][dis[x][dep[x]]]+=(x<=n);
    	fa[x][++dep[x]]=rt; dis[x][dep[x]]=d; int i;
    	for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!used[to[i]]) {
    		gd(to[i],x,rt,d+1);
    	}
    }
    void solve(int x) {
    	int i,al=tot;
    	used[x]=1; V[x][0].resize(al+2),V[x][1].resize(al+2); gd(x,0,x,0);
    	for(i=1;i<al+2;i++) V[x][0][i]+=V[x][0][i-1],V[x][1][i]+=V[x][1][i-1];
    	for(i=head[x];i;i=nxt[i]) if(!used[to[i]]) {
    		tot=siz[to[i]]; if(tot>siz[x]) tot=al-siz[x]; root=0; gr(to[i],x); solve(root);
    	}
    }
    int query(int x,int o,int v) {if(!x) return 0; if(v>int(V[x][o].size())-1) return sz[x]; return V[x][o][v];}
    int work(int x,int v) {if(v<0)return 0;int i,re=0; for(i=dep[x];i;i--) if(v>=dis[x][i]) re+=query(fa[x][i],0,v-dis[x][i])-query(fa[x][i+1],1,v-dis[x][i]); return re;}
    void d1(int x,int y) {
    	f[x]=y,d[x]=d[y]+1,siz[x]=1;int i;
    	for(i=head[x];i;i=nxt[i]) if(to[i]!=y) {
    		d1(to[i],x),siz[x]+=siz[to[i]];
    		if(siz[to[i]]>siz[son[x]]) son[x]=to[i];
    	}
    }
    void d2(int x,int t) {
    	top[x]=t; dfn[x]=++dfn[0]; idf[dfn[0]]=x; if(son[x]) d2(son[x],t); int i;
    	for(i=head[x];i;i=nxt[i]) if(to[i]!=f[x]&&to[i]!=son[x]) d2(to[i],to[i]);
    }
    int lca(int x,int y) {for(;top[x]!=top[y];y=f[top[y]]) if(d[top[x]]>d[top[y]]) swap(x,y);  return d[x]<d[y]?x:y;}
    int jmp(int x,int t) {for(;d[top[x]]>t;x=f[top[x]]); return idf[dfn[x]-(d[x]-t)];}
    inline bool cmp(const int &x,const int &y) {return dfn[x]<dfn[y];}
    void d3(int x) {p[++lm]=x; int i;if(!vis[x]) r[x]=-1;for(i=head[x];i;i=nxt[i])ff[to[i]]=x,d3(to[i]);head[x]=0;}
    int main() {
    	n=rd(); int i,x,y;
    	for(i=1;i<n;i++) {
    		x=rd(), y=rd(); add(x,n+i), add(n+i,x); add(y,n+i), add(n+i,y);
    	}
    	fk[0]=1<<30; tot=2*n-1; root=0; gr(1,0); solve(root); d1(1,0); d2(1,1);
    	int Q=rd(); memset(head,0,sizeof(head)); cnt=0;
    	while(Q--) {
    		m=rd(); cnt=ans=0;
    		for(i=1;i<=m;i++) p[i]=rd(),r[p[i]]=rd()<<1,vis[p[i]]=1;
    		sort(p+1,p+m+1,cmp); S[tp=1]=1;
    		for(i=1;i<=m;i++) {
    			x=p[i]; y=lca(x,S[tp]);
    			while(d[y]<d[S[tp]]) {
    				if(d[y]>=d[S[tp-1]]) {
    					add(y,S[tp]); tp--;
    					if(S[tp]!=y) S[++tp]=y;
    					break;
    				}
    				add(S[tp-1],S[tp]); tp--;
    			}
    			if(S[tp]!=x) S[++tp]=x;
    		}
    		while(tp>1) add(S[tp-1],S[tp]),tp--;
    		lm=0; d3(1);
    		for(i=lm;i>1;i--) r[ff[p[i]]]=max(r[ff[p[i]]],r[p[i]]-(d[p[i]]-d[ff[p[i]]]));
    		for(i=2;i<=lm;i++) r[p[i]]=max(r[p[i]],r[ff[p[i]]]-(d[p[i]]-d[ff[p[i]]]));
    		for(i=1;i<=lm;i++) ans+=work(p[i],r[p[i]]);
    		for(i=2;i<=lm;i++) {
    			x=p[i],y=ff[x];
    			int z=jmp(x,(d[x]-r[x]+d[y]+r[y])>>1);
    			ans-=work(z,r[x]-(d[x]-d[z]));
    		}
    		printf("%d
    ",ans);
    		for(i=1;i<=lm;i++) vis[p[i]]=0;
    	}
    }
    
    
  • 相关阅读:
    Java并发编程:如何创建线程?
    Java并发编程:volatile关键字解析
    Java并发编程:深入剖析ThreadLocal
    Java并发编程:同步容器
    Java ConcurrentModificationException异常原因和解决方法
    Java并发编程:并发容器之ConcurrentHashMap
    Java并发编程:并发容器之CopyOnWriteArrayList
    Java并发编程:Callable、Future和FutureTask
    rest-framework频率组件
    rest-framework的权限组件
  • 原文地址:https://www.cnblogs.com/suika/p/10165660.html
Copyright © 2020-2023  润新知