1. 程式人生 > >2018-10-18雜題選講

2018-10-18雜題選講

2018-10-18 雜題選講

T1 Distance Sums

給出一顆帶標號的樹的每個點到其他點的距離之和(每條邊長為1,保證距離之和兩兩不同),還原這棵樹的形態,如果不能還原輸出-1 (n<=10^5) 原題

數值最小的點是樹的重心,將它作為根。從大到小列舉數值,對於每個列舉到的點可以知道其子樹的大小,從而知道其父親的數值為d[u]-(n-2*size[u]),還原樹後檢驗根節點數值。

#include<bits/stdc++.h>
using namespace std;

#define fatherdis fd

long long ans=0,n,father[100010],size[100010],first[100010],nxt[200020],u[200020],v[200020],tot=0,tmp,fatherdis,pos,judge=0,j,root,depth[100010]={0};

struct csx
{
	long long num,dis;
}p[100010];

bool cmp(const csx a,const csx b)
{
	if (a.dis<b.dis) return true;
	else return false;
}

void add(long long from,long long to)
{
	tot++;
	nxt[tot]=first[from];
	first[from]=tot;
	u[tot]=from;
	v[tot]=to;
	return;
}

void dfs(long long point)
{
	long long k=first[point];
	while (k!=-1)
	{
		long long to=v[k];
		if (father[point]!=to)
		{
		    depth[to]=depth[point]+1;
			dfs(to);
		}
		k=nxt[k];
	}
	ans+=depth[point];
	return;
}

int main()
{
	memset(first,-1,sizeof(first));
	scanf("%lld",&n);
	for (int i=1;i<=n;i++) 
	{
		scanf("%lld",&tmp);
		size[i]=1;
	    p[i].num=i;
	    p[i].dis=tmp;
	}
	sort(p+1,p+n+1,cmp);
	root=p[1].num;
	for (int i=n;i>1;i--)
	{
		fd=p[i].dis-(n-2*size[p[i].num]);
		j=i-1;
		while (j>0&&p[j].dis!=fd) j--;
		if (!j) 
		{
			judge=1;
			break;
		}
		father[p[i].num]=p[j].num;
		size[p[j].num]+=size[p[i].num];
		add(p[j].num,p[i].num);
		add(p[i].num,p[j].num);
	}
	dfs(root);
	if (judge||ans!=p[1].dis) printf("-1");
	else for (int i=1;i<=tot/2;i++) printf("%lld %lld\n",u[i*2],v[i*2]);
	return 0;
}

提交記錄

T2 Sergey and Subway

給定一棵樹,將距離<=2的點連邊,所有邊權為1,求任意兩點最短距離之和(n<=10^5) 原題

對於任意兩點之間的距離,若原先距離為偶數則新距離是dis/2,若原距離是奇數,則新距離是dis/2+1。將樹黑白染色,對第二種答案對貢獻數量為白點數*黑點數。

#include<bits/stdc++.h>
using namespace std;
long long n,u[400040],v[400040],first[200020],nxt[400040],tot=0,size[200020],color[200020],father[200020];
long long black=0,white=0,dis=0,ans;

void add(long long from,long long to)
{
	tot++;
	nxt[tot]=first[from];
	first[from]=tot;
	u[tot]=from;
	v[tot]=to;
	return;
}

void dfs(long long point)
{
	size[point]=1;
	long long j=first[point];
	while (j!=-1)
	{
		long long to=v[j];
		if (father[point]!=to)
		{
			father[to]=point;
			color[to]=color[point]*(-1);
			dfs(to);
			size[point]+=size[to];
		}
		j=nxt[j];
	} 
	return;
}

int main()
{
	memset(first,-1,sizeof(first));
	scanf("%lld",&n);
	for (long long i=1;i<n;i++)
	{
		long long x,y;
		scanf("%lld%lld",&x,&y);
		add(x,y);
		add(y,x);
	}
	color[1]=1;
	dfs(1);
	for (long long i=1;i<=n;i++)
	{
		if (color[i]==1) black++;
		else if (color[i]==-1) white++; 
	}
	for (long long i=1;i<=tot/2;i++)
	{
		long long up=u[i*2],down=v[i*2];
		if (father[up]==down) swap(up,down);
		dis+=size[down]*(n-size[down]); 
	}
	ans=(dis+black*white)/2;
	printf("%lld",ans);
	return 0;
}

提交記錄