20161025的考试】贪心,特技乱搞树直径,仙人掌最短路

20 篇文章 0 订阅
6 篇文章 0 订阅

T1:

题意:给定1到n的排列,依次入栈,想什么时候pop什么时候pop,求字典序最大的出栈顺序

思路:显然是个贪心,每次比较当前栈顶和后缀max,栈顶大就pop,后缀max大就push。最后pop到空

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 1000005
using namespace std;	int n;

int a[MAXN],mx[MAXN];

int stk[MAXN],top=0;

char tmp[20];
inline int read(){
	scanf("%s",tmp);
	int rtn=0;
	for(register char *s=tmp;*s;++s)	rtn=rtn*10+*s-'0';
	return rtn;
}

inline void write(int x){
	memset(tmp,0,sizeof tmp);
	int cnt=0;
	while(x){
		tmp[cnt++]=x%10+'0';
		x/=10;
	}
	for(register int i=cnt-1;~i;--i)	putchar(tmp[i]);
	putchar(' ');
}

int main(){
	freopen("sort.in","r",stdin);
	freopen("sort.out","w",stdout);

	n=read();
	for(register int i=1;i<=n;++i)	a[i]=read();
	for(register int i=n;i;--i)	mx[i]=max(mx[i+1],a[i]);
	
	for(register int i=1;i<=n;++i){
		stk[++top]=a[i];
		while(stk[top]>mx[i+1])	write(stk[top--]);
	}
	
	while(top)	write(stk[top--]);
	return 0;
}

T2:

题面:一棵树,每次删除某条边,求当前森林中所有树的直径之积

思路:

        显然删边没有加边好写,于是倒着做。对于两棵树,在合并的时候,新树的直径肯定是原树中的某条路径,于是先nlogn地处理出来(随便倍增啊链剖啊啥的)。

        合并的新直径,有两种情况,一种是合并前的某棵树的直径,另一种是新产生的一条路径。

        可以yy出一个性质,合并时产生的直径的端点一定是原来直径的端点。

        于是求一下路径长度取个max就好

代码:

#include<bits/stdc++.h>
#define MAXN 100005
#define MOD 1000000007
using namespace std;	int n;
int ans=1;
//=========================================================
char read_s[30];
int read(){
	scanf("%s",read_s);
	int f=1;
	int rtn=0;
	for(char *s=read_s;*s;++s)
		if(*s==-1)	f=-1;
		else	rtn=rtn*10+*s-'0';
	return rtn*f;
}
//=========================================================
#define inv(x) pow_(x,MOD-2)
int pow_(int d,int c){
	int rtn=1;
	for(;c;c>>=1,d=1ll*d*d%MOD)
		if(c&1)
			rtn=1ll*rtn*d%MOD;
	return rtn;
}
//=========================================================  
struct t1{
	int frm,to,nxt;
}edge[MAXN<<1];	int cnt_edge=0;
int fst[MAXN];
void addedge(int x,int y){
	edge[++cnt_edge].to=y;
	edge[cnt_edge].frm=x;
	edge[cnt_edge].nxt=fst[x];
	fst[x]=cnt_edge;
}

int val[MAXN];
int fth[MAXN],top[MAXN],siz[MAXN],son[MAXN];
int dis[MAXN],dpt[MAXN];
void dfs1(int now){
	siz[now]=1;
	for(int tmp=fst[now];tmp;tmp=edge[tmp].nxt){
		int aim=edge[tmp].to;
		if(aim==fth[now])	continue;
		fth[aim]=now;
		dpt[aim]=dpt[now]+1;
		dis[aim]=dis[now]+val[aim];
		dfs1(aim);
		siz[now]+=siz[aim];
		if(siz[aim]>siz[son[now]])	son[now]=aim;
	}
}

void dfs2(int now,int tp){
	top[now]=tp;
	if(son[now])	dfs2(son[now],tp);
	for(int tmp=fst[now];tmp;tmp=edge[tmp].nxt){
		int aim=edge[tmp].to;
		if(aim==son[now]||aim==fth[now])	continue;
		dfs2(aim,aim);
	}
}

int _lca(int a,int b){
	while(top[a]^top[b]){
		if(dpt[fth[top[a]]]<dpt[fth[top[b]]])	swap(a,b);
		a=fth[top[a]];
	}
	return dpt[a]<dpt[b]? a:b;
}

int get_dis(int a,int b){
	int lca=_lca(a,b);
	return dis[a]+dis[b]-dis[lca]-dis[fth[lca]];
}
//===============================================================
int del[MAXN];

int father[MAXN];
int findfather(int x){return father[x]==x?x:father[x]=findfather(father[x]);}

int end[MAXN][2],length[MAXN];
int end_tmp[2];

int print[MAXN];

int read_x,read_y;
int main(){
//	freopen("forest.in","r",stdin);
//	freopen("forest.out","w",stdout);
	
	scanf("%d",&n);
	for(int i=1;i<=n;++i)	scanf("%d",val+i);
	for(int i=1;i<n;++i){
		scanf("%d%d",&read_x,&read_y);
		addedge(read_x,read_y);
		addedge(read_y,read_x); 
	}
	dis[1]=val[1];
	dpt[1]=1;
	dfs1(1);
	dfs2(1,1);
	
	for(int i=1;i<n;++i)	scanf("%d",del+i);

	for(int i=1;i<=n;++i)	end[i][0]=end[i][1]=father[i]=i,ans=1ll*ans*val[i]%MOD;
	for(int i=1;i<=n;++i)	length[i]=val[i];
	
	print[n] = ans;
	for(int i=n-1;i;--i){
		int u=edge[del[i]<<1].frm,v=edge[del[i]<<1].to;
		u = findfather( u ) , v = findfather( v );
		
		int ll;	
	
		if(length[v] > length[u])
			end_tmp[0]=end[v][0] , end_tmp[1]=end[v][1] , ll=length[v];
		else
			end_tmp[0]=end[u][0] , end_tmp[1]=end[u][1] , ll=length[u];
		
		ans = 1ll * ans * inv(length[v]) % MOD;
		ans = 1ll * ans * inv(length[u]) % MOD;
		
		for(int j=0;j<2;++j){
			for(int k=0;k<2;++k){
				int dd=get_dis(end[u][j],end[v][k]);
				if(dd > ll)
					end_tmp[0]=end[u][j] , end_tmp[1]=end[v][k] , ll=dd;
			}
		}
		
		if(i&1)	father[v]=u,length[u]=ll,end[u][0]=end_tmp[0],end[u][1]=end_tmp[1];
		else	father[u]=v,length[v]=ll,end[v][0]=end_tmp[0],end[v][1]=end_tmp[1];
		
		ans = 1ll * ans * ll % MOD; 
		print[i] = ans;
	}
	
	for(int i=1;i<=n;++i)	printf("%d\n",print[i]);
	
	return 0;
}

T3:

题面:仙人掌上最短路

思路:GG,缩环什么的,自己yy就好,tarjan啊………………反正我是背不住版

代码:http://blog.csdn.net/flaze_/article/details/52967247

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值