2015年藍橋杯C/C++省賽大學A組 災後重建 (樹上倍增最值+線段樹)

題目鏈接

100分的做法:

當p>sqrt(n)時, 這時候%p=c的點不超過sqrt(n)個, 直接倍增求路徑最值就好了

當p<=sqrt(n)時,將詢問離線, 按照p和c從小到大排序,同時處理出所有p相同且c相同的區間詢問
對於同一個p[i]和c[i],將所有%p[i]=c[i]的點, 兩兩(c[j]和c[j]+p)求路徑最大值, 並將這個相鄰最大值更新到線段樹上, 對於一個區間的詢問, 直接從線段樹上查[l,r]的區間最值

#pragma GCC optimize(2)
#include <cstdio>
#include <algorithm>
#include <vector>
#include <iterator>
#include <cmath>
#include <cstring>
#include <utility>

const int maxn = 5e4 + 5;

struct node
{
	int u,v,w;
	bool operator<(const node &x)const
	{
		return w<x.w;
	}
}edge[200005];

std::vector<node> v;
std::vector<std::pair<int,int> > G[maxn];
int a[maxn],res[maxn],dep[maxn],fa[maxn],Fa[maxn][17],ma[maxn][17],n,m,q;

int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}

void dfs(int u,int fa)
{
	dep[u]=dep[fa]+1;
	Fa[u][0]=fa;
	for(int i=1;(1<<i)<=dep[u];i++)
		Fa[u][i]=Fa[Fa[u][i-1]][i-1],
		ma[u][i]=std::max(ma[u][i-1],ma[Fa[u][i-1]][i-1]);
	for(std::vector<std::pair<int,int> >::iterator i=G[u].begin();i!=G[u].end();++i)
	{
		if(i->first==fa) continue;
		ma[i->first][0]=i->second;
		dfs(i->first,u);
	}
}
int getlca_max(int x,int y)
{
	int ans=-0x3f3f3f3f;
	if(dep[x]<dep[y]) std::swap(x,y);
	for(int i=16;i>=0;i--) if((1<<i)<=dep[x]-dep[y]) 
			ans=std::max(ans,ma[x][i]),x=Fa[x][i];
	if(x==y) return ans;
	for(int i=16;i>=0;i--)
		if(Fa[x][i]!=Fa[y][i])
			ans=std::max(ans,std::max(ma[y][i],ma[x][i])),
			x=Fa[x][i],y=Fa[y][i];
	return std::max(ans,std::max(ma[x][0],ma[y][0]));
}
struct SegTree
{
	int maxx[maxn<<2];
	void build(int o,int l,int r)
	{
		maxx[o]=0;
		if(l==r){maxx[o]=a[l];return ;}
		int m=(l+r)>>1;
		build(o<<1,l,m);build(o<<1|1,m+1,r);
		maxx[o]=std::max(maxx[o<<1],maxx[o<<1|1]);
	}
	int query(int o,int l,int r,int ql,int qr)
	{
		if(ql<=l&&r<=qr)return maxx[o];
		int m=(l+r)>>1;
		int ans=-0x3f3f3f3f;
		if(ql<=m) ans=std::max(ans,query(o<<1,l,m,ql,qr));
		if(qr>m) ans=std::max(ans,query(o<<1|1,m+1,r,ql,qr));
		return ans;
	}
}st;

struct query
{
	int l,r,mod,c,id;
	bool operator<(const query &x)const
	{
		if(mod==x.mod)return c<x.c;
		else return mod<x.mod;
	}
}Q[maxn];
int main()
{
#ifdef LOCAL
    freopen("input.in","r",stdin);
#endif
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++)
    {
    	scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
    }
    std::sort(edge+1,edge+m+1);
    int cnt=0;
    for(int i=1;i<=m;i++)
    {
    	int x=find(edge[i].u),y=find(edge[i].v);
    	if(x!=y)
    	{
    		fa[x]=y;cnt++;
    		G[edge[i].u].push_back(std::make_pair(edge[i].v,edge[i].w));
    		G[edge[i].v].push_back(std::make_pair(edge[i].u,edge[i].w));
    	}
    	if(cnt==n-1)break;
    }
    dfs(1,0);
    for(int i=1;i<=q;i++)
    {
    	int l,r,mod,c;scanf("%d%d%d%d",&Q[i].l,&Q[i].r,&Q[i].mod,&Q[i].c);
    	Q[i].id=i;
    }
    std::sort(Q+1,Q+q+1);
    for(int i=1;i<=q;i++)
    {
    	int l=Q[i].l,r=Q[i].r,mod=Q[i].mod,c=Q[i].c;
    	if(mod>sqrt(n))
    	{
    		int L=l-l%mod+c; if(L<l)L+=mod;
    		int ans=-0x3f3f3f3f;
    		for(int j=L;j<=r-mod;j+=mod)
    			ans=std::max(ans,getlca_max(j,j+mod));
    		res[Q[i].id]=ans;
    	}
    	else 
    	{
    		if(Q[i].mod!=Q[i-1].mod||Q[i].c!=Q[i-1].c)
    		{
    			memset(a,0,sizeof a);
    			for(int j=c?c:mod;j+mod<=n;j+=mod)
    				a[j]=getlca_max(j,j+mod);
    			st.build(1,1,n);
    		}
    		res[Q[i].id]=st.query(1,1,n,l,r-mod);
    	}
    }
    for(int i=1;i<=q;i++)printf("%d\n",res[i]);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章