ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解----牛半仙的妹子图

2021-07-29 20:01:36  阅读:148  来源: 互联网

标签:半仙 val read 题解 sum ---- int num ans


前言:

  来源于NOIP模拟27。
  考场上想出正解思路了,但是差个优化,所以没A。

基本思路:

  考虑牛半仙能不能到达一个妹子处取决于路径上最困难的那条路的值。
  又由于他会到达所有能到达的妹子,所以一定会选最大值最小的路径。
  考虑最小生成树,我用的kruscal。
  从x开始dfs记录到达每个妹子经过的最大的路径值。
  然后根据这个排序。
  从小到大统计妹子中数,那么就可以在排序后的序列上二分,对于给定权值找到可以去到的妹子的种数。
  朴素做法是枚举\(l\)到\(r\)的权然后一个个二分。
  会\(T\)。
  战神给了个优化:

\[sum[i]=sum[i-1]+(val_{i}-val_{i-1})*num[i-1] \]

  前缀优化。
  对于权值在\([val_{i-1},val_{i})\)的二分结果,一定是\(num[i-1]\),num是妹子种数。
  那么对这些结果前缀。
  记\(l\)二分的结果(下标)为\(x\),\(r\)的为\(y\),答案就是

\[sum[y]+num[y]*(r-val_{i})-(sum[x]+num[x]*(l-val_{x})) \]

  将\(O(n)\)优化为了\(O(1)\)。
  代码:

#include<bits/stdc++.h>
using namespace std;
namespace STD
{
	#define rr register 
	#define inf INT_MAX
	typedef long long ll;
	const int N=5e5+4;
	const int M=5e5+4;
	int n,m,q,root,opt;
	int mod;
	ll num[N],sum[N];
	bool vis[604];
	struct edge
	{
		int u,v,w;
		bool operator<(const edge b_) const
		{
			return w<b_.w;
		}
	}a[M];
	int to[N<<1],dire[N<<1],w[N<<1],head[N];
	struct girls
	{
		int c,maxn;
		bool operator<(const girls b_) const
		{
			return maxn<b_.maxn;
		}
	}g[N];
	inline void add(int f,int t,int val)
	{
		static int num1=0;
		to[++num1]=t;
		dire[num1]=head[f];
		head[f]=num1;
		w[num1]=val;
	}
	int read()
	{
		rr int x_read=0,y_read=1;
		rr char c_read=getchar();
		while(c_read<'0'||c_read>'9')
		{
			if(c_read=='-') y_read=-1;
			c_read=getchar();
		}
		while(c_read<='9'&&c_read>='0')
		{
			x_read=(x_read<<3)+(x_read<<1)+(c_read^48);
			c_read=getchar();
		}
		return x_read*y_read;
	}
	int f[N];
	int find(int x)
	{
		if(f[x]==x) return x;
		return f[x]=find(f[x]);
	}
	void join(int x,int y)
	{
		x=find(x),y=find(y);
		if(x!=y)
			f[y]=x;
	}
	void kruscal()
	{
		for(rr int i=1;i<=n;i++)
			f[i]=i;
		sort(a+1,a+1+m);
		int t=0;
		for(rr int i=1;i<=m;i++)
		{
			int x=a[i].u,y=a[i].v;
			if(find(x)!=find(y))
			{
				join(x,y);
				t++;
				add(x,y,a[i].w),add(y,x,a[i].w);
				if(t==n-1) break;
			}
		}
	}
	void dfs(int x,int f,int ma)
	{
		g[x].maxn=ma;
		for(rr int i=head[x];i;i=dire[i])
		{
			if(to[i]==f) continue;
			dfs(to[i],x,max(w[i],ma));
		}
	}
	int find_pos(int val)
	{
		int l=1,r=n;
		while(l<r)
		{
			int mid=(l+r+1)>>1;
			if(g[mid].maxn<=val) l=mid;
			else r=mid-1;
		}
		return l;
	}
};
using namespace STD;
int main()
{
	n=read(),m=read(),q=read(),root=read(),opt=read();
	if(opt) mod=read();
	for(rr int i=1;i<=n;i++)
		g[i].c=read();
	for(rr int i=1;i<=m;i++)
	{
		a[i].u=read();
		a[i].v=read();
		a[i].w=read();
	}
	kruscal();
	dfs(root,root,0);
	sort(g+1,g+1+n);
	for(rr int i=1;i<=n;i++)
	{
		if(!vis[g[i].c])
		{
			num[i]=num[i-1]+1;
			vis[g[i].c]=1;
		}
		else num[i]=num[i-1];
	}
	//有意思的优化:
	for(rr int i=1;i<=n;i++)
		sum[i]=sum[i-1]+(g[i].maxn-g[i-1].maxn)*num[i-1];
	ll lastans=0;
	while(q--)
	{
		int l=read(),r=read();
		if(opt)
		{
			l=(l^lastans)%mod+1;
			r=(r^lastans)%mod+1;
			if(l>r) swap(l,r);
		}
		ll ans=0;
		int x=find_pos(l),y=find_pos(r);
		ans=sum[y]+num[y]*(r-g[y].maxn+1);
		ans-=(sum[x]+num[x]*(l-g[x].maxn));
		printf("%lld\n",ans);
		lastans=ans;
	}
}

标签:半仙,val,read,题解,sum,----,int,num,ans
来源: https://www.cnblogs.com/Geek-Kay/p/15076816.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有