4.10 The minimum spanning tree of the simulation game is optimized for construction

avatar
avatar

This question is super wonderful.

At 30 points, you can find that there are at most n pictures in the title, and the rest are useless, so you can build nQ pieces violently and run Cruzkar.

For Q <= 50, it is found that the number of edges at this time is 2e7, and it is necessary to run Cruiser GG.

Consider prim to find the minimum spanning tree complexity nlogn + 2e7.

So you can get 50 points for violence.

Finally, consider the case of (ai-bi) <= 1.

It can be found that at this time, the connected edge has characteristics. For ai <bi, the connected edge is 2,1 3,2 4,3 ... f [i] [0] means that the edge right of i is connected to its father.

For ai == bi it is almost the same as above.

For ai> bi, one of the same cases as above will also find that there are 4, 2 5, 3 6, 4 such a connected edge method f [i] [1] represents the edge right of the point i and the father of his father. That's it.

Using the f array to update other f values ​​can find that there is a ring, so dp can be twice. I was stupid at that time to open the smallest f array and update it.

Then do the minimum spanning tree complexity nlogn.

80 points code:

const int maxn=200010;
int n,flag,Q,vis[maxn];
vector<pii>g[maxn];
struct wy{int x,y,z;}t[maxn];
int d[maxn];ll sum;
priority_queue<pii>q;
int f[maxn][2];
inline void add(int x,int y,int z)
{
	if(z>=INF)return;
	if(x==y)return;
	g[x].pb(mk(y,z));
	g[y].pb(mk(x,z));
}
inline void prim()
{
	rep(1,n,i)d[i]=INF,vis[i]=0;
	d[1]=0;q.push(mk(-d[1],1));
	while(q.size())
	{
		int x=q.top().S;q.pop();
		if(vis[x])continue;
		vis[x]=1;sum+=d[x];
		for(int j=0;j<g[x].size();++j)
		{
			int tn=g[x][j].F,e=g[x][j].S;
			if(d[tn]>e)
			{
				d[tn]=e;
				q.push(mk(-d[tn],tn));
			}
		}
	}
}
int main()
{
	freopen("spanning.in","r",stdin);
	freopen("spanning.out","w",stdout);
	get(n);get(Q);
	rep(1,Q,i)
	{
		int x,y,z;
		get(x);get(y);get(z);
		t[i]=(wy){x,y,z};
		if(abs(x-y)>1)flag=1;
	}
	if(!flag)
	{
		rep(0,n-1,i)f[i][0]=f[i][1]=INF;
		rep(1,Q,i)
		{
			int x,y,z;
			x=t[i].x;y=t[i].y;z=t[i].z;
			if(x==y){f[(x+1)%n][0]=min(f[(x+1)%n][0],z+1);continue;}
			if(x<y)f[y][0]=min(f[y][0],z);
			else
			{
				f[x][0]=min(f[x][0],z);
				f[(x+1)%n][1]=min(f[(x+1)%n][1],z+1);
			}
		}
		rep(0,n-1,i)
		{
			if(f[i][1]!=INF)q.push(mk(-f[i][1],i));
			if(f[i][0]!=INF)q.push(mk(-f[i][0],i));
		}
		while(q.size())
		{
			int x=q.top().S;
			int ww=-q.top().F;
			q.pop();
			if(ww==f[x][0])
			{
				int tn=(x+1)%n;
				if(f[tn][0]>f[x][0]+2)
				{
					f[tn][0]=f[x][0]+2;
					q.push(mk(-f[tn][0],tn));
				}
			}
			if(ww==f[x][1])
			{
				int tn=(x+1)%n;
				if(f[tn][1]>f[x][1]+2)
				{
					f[tn][1]=f[x][1]+2;
					q.push(mk(-f[tn][1],tn));
				}
			}
		}
		rep(1,n-1,i)
		{
			add(i+1,i,f[i][0]);
			if(i>=2)add(i+1,i-1,f[i][1]);
		}
		add(1,n,f[0][0]);
		add(1,n-1,f[0][1]);
		add(2,n,f[1][1]);
		prim();putl(sum);
		return 0;
	}
	if(flag)
	{
		if((ll)n*Q<=10000000)
		{
			rep(1,Q,i)
			{
				int x=t[i].x;int y=t[i].y;int z=t[i].z;
				int s1=0,s2=0;add(x+1,y+1,z);
				rep(1,n*2-1,j)
				{
					if(j&1)++s1;else ++s2;
					add((s1+x)%n+1,(s2+y)%n+1,z+j);
				}
			}
			sum=0;prim();putl(sum);
		}
	}
	return 0;
}

Considering 100 points, we can still find that this is a problem of optimizing construction.

Consider the process of Kruskal. For edges a, b, and ca, connect b to a side of c. For the next side, a + 1, b, c + 1. When the previous edge is smaller than the current edge weight, when the previous edge is convenient, a, b must form a fast connection.

At this time, the side a + 1, b, c + 1 is equivalent to a + 1, a, c + 1 and the next side a + 1, b + 1, c + 2 can be converted to b, b + 1, c + 2.

Let f [i] represent the minimum dp of the edge weight of point i and its father's connected edges. It can be found that all the edges are simplified in this way.

Then run Cruiser to get the total number of edges Q + n. Complexity (Q + n) log.

const int MAXN=400010;
int n,cnt,Q;ll sum;
struct wy
{
	int x,y,z;
}t[MAXN<<1];
int f[MAXN];
inline int cmp(wy a,wy b){return a.z<b.z;}
inline int getfather(int x){return x==f[x]?x:f[x]=getfather(f[x]);}
int main()
{
	freopen("spanning.in","r",stdin);
	freopen("spanning.out","w",stdout);
	memset(f,0x3f,sizeof(f));
	get(n);get(Q);
	rep(1,Q,i)
	{
		int x,y,z;
		get(x);get(y);get(z);
		t[++cnt]=(wy){x+1,y+1,z};
		f[(x+1)%n]=min(f[(x+1)%n],z+1);
		f[(y+1)%n]=min(f[(y+1)%n],z+2);
	}
	rep(1,n-1,i)f[i]=min(f[i-1]+2,f[i]);
	f[0]=min(f[n-1]+2,f[0]);
	rep(1,n-1,i)f[i]=min(f[i-1]+2,f[i]);
	rep(1,n-1,i)t[++cnt]=(wy){i,i+1,f[i]};
	t[++cnt]=(wy){1,n,f[0]};
	rep(1,n,i)f[i]=i;
	sort(t+1,t+1+cnt,cmp);
	rep(1,cnt,i)
	{
		int xx=getfather(t[i].x);
		int yy=getfather(t[i].y);
		if(xx==yy)continue;
		f[xx]=yy;sum+=t[i].z;
	}
	putl(sum);
	return 0;
}

Guess you like

Origin www.cnblogs.com/chdy/p/12681854.html