• P3920 [WC2014]紫荆花之恋


    https://www.luogu.com.cn/problem/P3920

    \(l\)\((i,j)\) 路径上一点,则有:

    \[dis(i,j)\le r_i+r_j \Rightarrow dis(i,l)+dis(j,l)\le r_i+r_j\Rightarrow dis(i,l)-r_i\le r_j-dis(j,l) \]

    当插入一个新的 \(j\) 时,就拿着 \(k=r_j-dis(j,l)\) 去每个 \(l\) 找有多少 \(i\) 满足 \(dis(i,l)-r_i\le k\)
    那自然就是放到点分树上,用平衡树维护,每次查询排名,查完把 \(dis(j,l)-r_j\) 插入到每个点的平衡树上,当然每个点实际上是两个平衡树,因为还要容斥,不过这和别的题都差不多

    如何处理动态插入?用类似替罪羊树的方法,每次插入时如果某点的最大子树(点分树上的)大小超过他本身大小的 \(\alpha\) 倍,就重构整个子树
    为了方便可以给每个点维护一个 vector 存他所有的后代(点分树上),重构时就清空所有后代的平衡树,而这些后代在原树上一定是形成了一个连通块,标记下来在上面正常建点分树就行了
    然后对于每个后代,跳链修改他们所有祖先的平衡树
    由于单次重构是 \(O(n\log^2 n)\) 的不同于替罪羊树的 \(O(n)\),所以这个 \(\alpha\) 要取得大一些,大概 \(0.8\) 左右

    然后发现平衡树跑得又慢码量又大,清空树的时候还要手动回收空间,可以用 vector 根号重构来替代

    • 维护一个小 vector 一个大 vector,插入的时候往小 vector 里插入,如果大小超过了根号就归并进保持元素有序的大 vector
    • 查询的时候大 vectorupper_bound,小 vector 上暴力查询

    其实没多难写(

    #define N 100006
    #define M 200006
    #define LOG_N 17
    int n;
    struct SqrtRebuild{
    #define B 300 
    	std::vector<int>v,added,tmp;
    	inline void insert(int x){added.push_back(x);}
    	inline int rank(int x){
    		if(added.size()>B){
    			std::sort(added.begin(),added.end());
    			int i=0,j=0,s1=v.size(),s2=added.size();
    			tmp.resize(s1+s2);
    			while(i<s1&&j<s2){
    				if(v[i]<added[j]) tmp[i+j]=v[i],i++;
    				else tmp[i+j]=added[j],j++;
    			}
    			while(i<s1) tmp[i+j]=v[i],i++;
    			while(j<s2) tmp[i+j]=added[j],j++;
    			std::swap(v,tmp);
    			std::vector<int>().swap(added);
    		}
    		int ans=std::upper_bound(v.begin(),v.end(),x)-v.begin();
    		for(int i:added) ans+=i<=x;
    		return ans;
    	}
    	inline void clear(){std::vector<int>().swap(v);std::vector<int>().swap(added);}
    	inline unsigned int size(){return v.size()+added.size();}
    #undef B
    }T[N],Tfa[N];
    int fa[N],val[N];
    struct Graph{
    	int fir[N],nex[M],to[M],tot;
    	int fa[19][N],deep[N],sum[N];
    	inline void add(int u,int v,int w){//u(fa) -> v(son)
    		to[++tot]=v;nex[tot]=fir[u];fir[u]=tot;to[++tot]=u;nex[tot]=fir[v];fir[v]=tot;
    		deep[v]=deep[u]+1;sum[v]=sum[u]+w;fa[0][v]=u;
    		for(int j=1;j<=LOG_N;j++) fa[j][v]=fa[j-1][fa[j-1][v]];
    	}
    	inline int getLca(int u,int v){
    		if(deep[u]<deep[v]) lib::swap(u,v);
    		for(int j=LOG_N;~j;j--)if(deep[fa[j][u]]>=deep[v]) u=fa[j][u];
    		if(u==v) return u;
    		for(int j=LOG_N;~j;j--)if(fa[j][u]^fa[j][v]) u=fa[j][u],v=fa[j][v];
    		return fa[0][u];
    	}
    	inline int getDis(int u,int v){return sum[u]+sum[v]-(sum[getLca(u,v)]<<1);}
    	int allow[N],size[N],maxson[N],root;
    	void findRoot(int u,int fa=0){
    		size[u]=1;maxson[u]=0;
    		for(int v,i=fir[u];i;i=nex[i]){
    			v=to[i];
    			if(!allow[v]||v==fa) continue;
    			findRoot(v,u);size[u]+=size[v];
    			lib::chkMax(maxson[u],size[v]);
    		}
    		lib::chkMax(maxson[u],size[0]-size[u]);
    		if(maxson[u]<maxson[root]) root=u;
    	}
    	void divide(int u,int tot){
    		allow[u]=0;
    		for(int v,i=fir[u];i;i=nex[i]){
    			v=to[i];
    			if(!allow[v]) continue;
    			size[0]=size[v]>size[u]?(tot-size[u]):size[u];root=0;maxson[0]=_INT_INF;
    			findRoot(v);::fa[root]=u;divide(root,size[v]);
    		}
    	}
    }G;
    #define alpha 0.8 
    std::vector<int>son[N];
    inline void change(int u,int top){
    	for(int i=u;i^top;i=fa[i]) T[i].insert(G.getDis(u,i)-val[u]),fa[i]?Tfa[i].insert(G.getDis(u,fa[i])-val[u]):void(),son[i].push_back(u);
    }
    void rebuild(int u){
    	static int tmp[N];tmp[0]=0;
    	for(int v:son[u])if(v^u) std::vector<int>().swap(son[v]),T[v].clear(),Tfa[v].clear(),G.allow[v]=1,fa[v]=0,tmp[++tmp[0]]=v;
    	std::vector<int>().swap(son[u]);T[u].clear();Tfa[u].clear();G.allow[u]=1;tmp[++tmp[0]]=u;
    	int fau=fa[u];fa[u]=0;
    	G.size[0]=tmp[0];G.root=0;G.maxson[0]=_INT_INF;
    	G.findRoot(u);fa[G.root]=fau;G.divide(G.root,G.size[u]);
    	for(int i=1;i<=tmp[0];i++) change(tmp[i],fau);
    }
    void insert(int u,int f){
    	fa[u]=f;change(u,0);
    	int badtag=0;
    	for(int i=u;fa[i];i=fa[i]){
    		if(son[i].size()>son[fa[i]].size()*alpha+5) badtag=fa[i];
    		i=fa[i];
    	}
    	if(badtag) rebuild(badtag);
    }
    #undef alpha
    long long ans;
    inline void ask(int u,int k){
    	for(int last=0,dis,i=u;i;i=fa[i]){
    		dis=G.getDis(u,i);
    		ans+=T[i].rank(k-dis);
    		if(last) ans-=Tfa[last].rank(k-dis);
    		last=i;
    	}
    }
    int main(){
    	read();n=read();
    	read();read();val[1]=read();
    	G.deep[1]=1;insert(1,0);write("0\n");
    #define MOD 1000000000
    	for(int fa,w,i=2;i<=n;i++){
    		fa=read()^(ans%MOD);w=read();val[i]=read();
    		G.add(fa,i,w);
    		ask(fa,val[i]-w);insert(i,fa);
    		writeEN(ans);
    	}
    	return RET;
    }
    
  • 相关阅读:
    并不对劲的CF1236D&E:Alice&Doll&UnfairGame
    并不对劲的CF1194E:Count The Rectangles
    并不对劲的CF1239B&C&D Programming Task in the Train to Catowice City
    并不对劲的初赛蒙猜凑思路
    并不对劲的CF1237D&E:Balanced Playlist and Binary Search Trees
    并不对劲的???
    并不对劲的P5589
    (简单) POJ 1511 Invitation Cards,SPFA。
    (简单) POJ 3159 Candies,Dijkstra+差分约束。
    (简单) POJ 2502 Subway,Dijkstra。
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/15927654.html
Copyright © 2020-2023  润新知