zoukankan      html  css  js  c++  java
  • 题解-hzy loves segment tree I

    Problem

    题目概要:给定一棵 (n) 个节点的树,点有点权,进行 (m) 次路径取(max)的操作,最后统一输出点权

    (nleq 10^5,mleq 5 imes 10^6)

    Thoughts

    今天闲来无事想到的题目,然后就出出来了

    我的做法复杂度是(O(nlog n+m)),想把(O(mlog m))卡掉,于是一开始把 (m) 开到了(10^7),后来发现由于常数过大,导致需要跑(7s) 虽然其他做法都跑不出来,然后就把数据开小到(5 imes 10^6),本机(1.5s)

    后来有人利用stl超高速的(sort)过了这题,但需要(O(m))的空间,同样可以卡掉 但凭借着与(m)无关的空间复杂度,还是可以将其卡掉

    Solution

    首先这题有个可并堆的(O(mlog m))的做法,并过不去

    算了,还是讲我的做法,这是一个预处理(O(nlog n)),单次操作(O(1))的做法

    首先套路地将路径按照(lca)进行拆分,然后将可以利用st表进行区间标记(然后最后再将所有st表里的东西逐层下传)

    由于st表是利用两个可重区间将整个区间进行覆盖,需要找到对应的区间端点的位置,在序列上可以直接找下标,但在树上呢……直接找(k)祖先!

    好了,其实这就是一道st表找lca+长链剖分求(k)祖先+st表逆向应用的三合一(其实这些操作之间可以共用许多东西)

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    inline void read(int&x){
    	char c11=getchar();x=0;while(!isdigit(c11))c11=getchar();
    	while(isdigit(c11))x=x*10+c11-'0',c11=getchar();
    }
    
    inline void cmax(int&A,int B){A=A>B?A:B;}
    
    const int N=100003;
    struct Edge{int v,nxt;}a[N+N];
    int head[N],n,m,_;
    
    inline void ad(){
    	int u,v;read(u),read(v);
    	a[++_].v=v,a[_].nxt=head[u],head[u]=_;
    	a[++_].v=u,a[_].nxt=head[v],head[v]=_;
    }
    
    namespace data{
    	typedef long long ll;
    	const int p=1e9+7;
    	int u0,u1,v0,v1,w0,w1,i;
    	inline void reset(){read(u0),read(u1),read(v0),read(v1),read(w0),read(w1);i=0;}
    	inline void get(int&u,int&v,int&w){
    		++i;if(i==1){u=u1,v=v1,w=w1;return ;}
    		u=((ll)i*u1+(ll)(i+1)*u0)%n+1;u0=u1,u1=u;
    		v=((ll)i*v1+(ll)(i+1)*v0)%n+1;v0=v1,v1=v;
    		w=((ll)i*w1+(ll)(i+1)*w0)%p+1;w0=w1,w1=w;
    	}
    }
    
    int fa[N],son[N];
    int dep[N],len[N],top[N];
    int dfs_seq[N+N],dfc;
    int in[N],out[N];
    
    void main_dfs(int x,int las){
    	dep[x]=dep[fa[x]=las]+1;
    	in[x]=++dfc;dfs_seq[dfc]=x;
    	for(int i=head[x];i;i=a[i].nxt)
    		if(a[i].v!=las){
    			main_dfs(a[i].v,x);
    			dfs_seq[++dfc]=x;
    			if(len[a[i].v]>len[son[x]])
    				son[x]=a[i].v;
    		}
    	out[x]=dfc;
    	len[x]=len[son[x]]+1;
    }
    
    namespace ST{
    	int f[20][N],anc[20][N];
    	void main(){
    		for(int i=1;i<=n;++i)
    			anc[0][i]=fa[i];
    		for(int j=1;j<20;++j)
    			for(int i=1;i<=n;++i)
    				anc[j][i]=anc[j-1][anc[j-1][i]];
    	}
    	void print(){
    		for(int j=19;j;--j)
    			for(int i=1;i<=n;++i){
    				cmax(f[j-1][i],f[j][i]);
    				cmax(f[j-1][anc[j-1][i]],f[j][i]);
    			}
    		for(int i=1;i<=n;++i)
    			printf("%d
    ",f[0][i]);
    	}
    }
    
    namespace lca{
    	int st_f[20][N+N],Log[N+N];
    	inline int get(int x,int y){
    		int l = min(in[x], in[y]), r = max(out[x], out[y]);
    		int w = Log[r-l+1];
    		int t1=st_f[w][l],t2=st_f[w][r-(1<<w)+1];
    		return dep[t1]<dep[t2]?t1:t2;
    	}
    	void main(){
    		Log[0]=-1;
    		for(int i=1;i<=dfc;++i)
    			st_f[0][i]=dfs_seq[i],Log[i]=Log[i>>1]+1;
    		for(int l=1,len=1;len<=dfc;++l,len<<=1)
    		for(int i=1;i+len-1<=dfc;++i)
    			st_f[l][i]=dep[st_f[l-1][i]]<dep[st_f[l-1][i+len]]?st_f[l-1][i]:st_f[l-1][i+len];
    		return ;
    	}
    }
    
    namespace kth_anc{
    	const int ks=5;
    	int up[N*ks],down[N*ks];
    	int hbit[N];
    	int tot_up,tot_down;
    	int down_be[N];
    	int up_be[N];
    	inline int get(int x,int k){
    		if(!k)return x;
    		int t=hbit[k];
    		x=ST::anc[t][x];
    		k-=(1<<t)+dep[x]-dep[top[x]];
    		x=top[x];
    		if(!k)return x;
    		if(k>0)return up[up_be[x]+k];
    		return down[down_be[x]-k];
    	}
    	void dfs(int x,int Top){
    		top[x]=Top;
    		if(son[x])dfs(son[x],Top);
    		for(int i=head[x];i;i=a[i].nxt)
    			if(a[i].v!=fa[x] and a[i].v!=son[x])
    				dfs(a[i].v,a[i].v);
    	}
    	void main(){
    		dfs(1,1);
    		for(int i=1;i<=n;++i)
    			if(top[i]==i){
    				int x=i,t=min(len[x],dep[x]);
    				up_be[i]=tot_up;
    				while(t--)up[++tot_up]=fa[x],x=fa[x];
    				x=i,t=len[x];
    				down_be[i]=tot_down;
    				while(t--)down[++tot_down]=son[x],x=son[x];
    			}
    		for(int i=1;i<=n;++i)hbit[i]=-1;
    		for(int j=20;~j;--j)
    		for(int i=1<<j;i<=n;++i)
    			if(-1==hbit[i])
    				hbit[i]=j;
    	}
    }
    
    void solve(int o,int x,int w){
    	int dis=dep[x]-dep[o]+1,t=lca::Log[dis];
    	cmax(ST::f[t][x],w);
    	if(dis==(1<<t))return ;
    	x=kth_anc::get(x,dis-(1<<t));
    	cmax(ST::f[t][x],w);
    }
    
    int main(){
    	read(n),read(m);
    	for(int i=1;i<=n;++i)read(ST::f[0][i]);
    	for(int i=1;i<n;++i)ad();
    	main_dfs(1,0);
    	ST::main();
    	lca::main();
    	kth_anc::main();
    	data::reset();
    	for(int i=1;i<=m;++i){
    		int x,y,w,o;
    		data::get(x,y,w);
    		o=lca::get(x,y);
    		solve(o,x,w),solve(o,y,w);
    	}
    	ST::print();
    	return 0;
    }
    
  • 相关阅读:
    linux安装skype
    (转)程序员最应该读的图书
    Smarty 学习笔记六 缓存
    Smarty 学习笔记二 常用内置变量
    Smarty 学习笔记七 debug
    文本文件与二进制文件区别
    zz 通用线程:Awk 实例,第 2部分
    MIT墙上的格言
    AWK学习笔记
    zz SED单行脚本快速参考 以及 AWK版本
  • 原文地址:https://www.cnblogs.com/penth/p/10268322.html
Copyright © 2011-2022 走看看