BZOJ 2125 最短路 && BZOJ 3047 Freda的传呼机【仙人掌最短路

…………仙人掌啊,亦可赛艇

…………好嘛…………写的欲仙欲死23333

前几天考试的题233今天终于过了


根据某blog,仙人掌是植物,所以当成树来做就好了【xxx

于是遇到环的话,吧环顶当成环上其他节点的LCA,连上边长为这个点到环顶的距离的边,在新的树上跑树上路径长度就好了。

这样建树的话还可以知道是从哪个节点进入环的

然而如果是出现了LCA是某个环的环顶的话,显然这样可能不是最优的,于是对于环上的两个点,显然距离是两半二选一,于是记录一下按照找环时遍历的顺序,得到的节点和环顶的距离,相减后和它的补取个min就好了


啊顺便 这个大爷 的码风我喜欢23333【找到个码风相近的人不容易啊【虽然现在我的码风越来越毒瘤了2333


啊…………WA了一年,最后发现…………缩环标记环顶的时候写崩了2333

我是在找完环之后再补全原树上的边的,于是GG了


在dfs遍历找环的时候,如果遇到返祖边(假设指向aim),应该把当前整个栈里的元素的环顶标记成aim。但是并不应该对aim进行操作(因为仙人掌的话,一个节点可以在多个环中),所以在这个时候,aim并没有标记环顶。

显然应该在dfs结束之后,对于所有没有标记环顶的节点,把环顶标记成自己(如果是单节点的话就当成一元环嘛233),这样再复原原图中的边的时候就不会出锅


代码【码力太渣写到想死x】【不过A了真的迷之快♂感啊2333】【lxl大爷表示:你们啊naive,我一遍就A了】

【嗯读入优化是个好东西啊23333】

↓从上到下是nzhtl1477大爷的fread,fwrite;咸鱼读优;没有优化


总之谢谢lxl的读入输出优化模板w

#include
#define MAXN 10005
using namespace std;	int n,m,q;
//==================================================
struct io_t{
	char op[3<<20];
	char* s;
	int a[24];
	char ed[1<<20];
	char* t;
	io_t():s(op),t(ed){
		fread(s,1,
		sizeof op,stdin);
	}
	~io_t(){
		fwrite(ed,1,
		t-ed,stdout);
	}
	void scan(char* q){
		while(*s<48)
			++s;
		while(*s>32)
			*q++=*s++;
		*q=0;
	}
	void print(const
	char* q){
		while(*q)
			*t++=*q++;
		*t++=10;
	}
	int scan(){
		static int v,j;
		v=0,j=1;
		while(*s<48)
			j=*s++^45;
		do
			v=v*10+*s++-48;
		while(*s>32);
		return j?v:-v;
	}
	template< class T >
	void print( register T v){
		static int* q=a;
		if(!v)*t++=48;
		else{
			if(v<0)
				*t++=45,
				v*=-1;
			while(v)
				*q++=v%10+48,
				v/=10;
			while(q!=a)
				*t++=*--q;
		}
		*t++=10;
	}
}io;
//==========================================================

struct t1{
	int to,nxt,lth;
	int tag;
	t1(){}
	t1(int to,int nxt,int lth):to(to),nxt(nxt),lth(lth){}
}edge[MAXN<<2],edge_2[MAXN<<2];	int cnt_edge=1,cnt_edge_2=0;
int fst[MAXN],fst_2[MAXN];
inline void addedge(int x,int y,int l){
	edge[++cnt_edge]=t1(y,fst[x],l);
	fst[x]=cnt_edge;
	edge[++cnt_edge]=t1(x,fst[y],l);
	fst[y]=cnt_edge;
}
inline void addedge_2(int x,int y,int l){
	edge_2[++cnt_edge_2]=t1(y,fst_2[x],l);
	fst_2[x]=cnt_edge_2;
	edge_2[++cnt_edge_2]=t1(x,fst_2[y],l);
	fst_2[y]=cnt_edge_2;
}
//=======================================================
int tot[MAXN]; 
int root[MAXN];
int dis[MAXN];
int dis_to_top[MAXN];
int dfn[MAXN],cnt_dfs=0;
int siz[MAXN];
int is_root[MAXN];

int col[MAXN],cnt_col=0;

int stk[MAXN],top_s=0;

int anc[MAXN][18];

void dfs(int now,int pre){
	dfn[now]=++cnt_dfs;
	stk[++top_s]=now;
	anc[now][0]=pre;
	for(register int tmp=fst[now];tmp;tmp=edge[tmp].nxt){
		int aim=edge[tmp].to;
		if(aim==pre)	continue;
		if(dfn[aim]){
			if(dfn[aim]i)	printf("( %d , %d ,lth = %d)\n",i,edge_2[j].to,edge_2[j].lth);
//	puts("\n");

	for(int i=1;i<=n;++i)	if(!root[i])	root[i]=i;

	for(int i=1;i<=n;++i)
		for(register int j=fst[i];j;j=edge[j].nxt){
			int aim=edge[j].to;
			if((root[i]^root[aim])&&(!edge[j].tag)&&(i^root[aim])&&(aim^root[i]))
				addedge_2(i,aim,edge[j].lth),edge[j].tag=edge[j^1].tag=1;
		}

//	for(int i=1;i<=n;++i)
//		for(int j=fst_2[i];j;j=edge_2[j].nxt)
//			if(edge_2[j].to>i)	printf("( %d , %d ,lth = %d)\n",i,edge_2[j].to,edge_2[j].lth);

	memset(anc,0,sizeof anc);
	memset(dis,0,sizeof dis);
	dpt[1]=1;
	dfs_2(1);

//	for(int i=1;i<=n;++i)	printf("%d\n",dis[i]);

	for(int i=1;i<=q;++i){
		read_x=read(),read_y=read();		
//		printf("dis ( %d , %d ) = ",read_x,read_y); 
		print(inqry(read_x,read_y));
	}
	return 0;
}


你可能感兴趣的:(OI,LCA,BZOJ,仙人掌)