hdu 6039 Gear Up

  OvO http://acm.hdu.edu.cn/showproblem.php?pid=6039

  (2017 Multi-University Training Contest 1 1007)

  诶嘿嘿 终于过了

  我还以为像我这么菜过这题要用很久呢

  结果真的用了很久……淦。

  用wi代表i的角速度,ri代表i的角度,则共享线速度的两个齿轮x,y的角速度满足log2(wx)+log2(rx)==log2(wy)+log2(ry)

  必然是要对这些齿轮建树的,最后建出来一个森林,然后每个森林取根节点为对照,则整棵树的速度都可以以此为参照用上面那个等式推导出来

  然后把节点分2类,一类是他有父亲的(树中,这个节点的上方,有齿轮和他共享线速度),一类是他没父亲的(树中,这个节点的上方,没有齿轮),前者和后者修改半径的话,对子树的影响是不一样的。

  1.修改前者的半径话,他共轴的节点为根的子树以及他本身的角速度会发生改变

  2.后者的话,以他为根的子树(不包括他)角速度会发生改变

  之后就是按DFS序建一颗线段树(区间最值)

  (思路来自汪汪汪一个卖鲜奶的的博客)

  

  

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>

#define log2(x) log(x)/log(2)
#define pow2(x) pow(2,x)

using namespace std;

const int M=1e5+44;

struct Edge
{
	int u,v,d;	
};

int n,m,q,r[M];
int fa[M];
int l1[M],r1[M],l2[M],r2[M];
int init_val[M];
int now;
int frt[M],chg[M];
vector<int> v[M];
vector<Edge> edge[M];

int tree[M*3],tag[M*3];

void build(int rt,int li,int ri)
{
	tag[rt]=0;
	if(li==ri)
	{
		tree[rt]=init_val[ri];
		return ;
	}
	int mid=(li+ri)>>1,lc=(rt<<1),rc=(rt<<1)+1;
	build(lc,li,mid);
	build(rc,mid+1,ri);
	tree[rt]=max(tree[lc],tree[rc]);
}

void pushdown(int rt,int li,int ri)
{
	if(li==ri)
	{
		tag[rt]=0;
		return ;
	}
	int mid=(li+ri)>>1,lc=(rt<<1),rc=(rt<<1)+1;
	tree[lc]+=tag[rt];
	tree[rc]+=tag[rt];
	tag[lc]+=tag[rt];
	tag[rc]+=tag[rt];
	tag[rt]=0;
}

void update(int rt,int li,int ri,int lq,int rq,int val)	//add
{
	if(lq<=li && ri<=rq)
	{
		tag[rt]+=val;
		tree[rt]+=val;
		return ;
	}
	int mid=(li+ri)>>1,lc=(rt<<1),rc=(rt<<1)+1;
	if(tag[rt])
		pushdown(rt,li,ri);
	if(mid>=lq)
		update(lc,li,mid,lq,rq,val);
	if(mid+1<=rq)
		update(rc,mid+1,ri,lq,rq,val);
	tree[rt]=max(tree[lc],tree[rc]);
}

int query(int rt,int li,int ri,int lq,int rq)	//get max
{
	int ret=-1e9-7;
	if(lq<=li && ri<=rq)
		return tree[rt];
	int mid=(li+ri)>>1,lc=(rt<<1),rc=(rt<<1)+1;
	if(tag[rt])
		pushdown(rt,li,ri);
	if(mid>=lq)
		ret=max(ret,query(lc,li,mid,lq,rq));
	if(mid+1<=rq)
		ret=max(ret,query(rc,mid+1,ri,lq,rq));
	return ret;
}

int fff(int x)
{
	if(fa[x]==x)
		return x;
	fa[x]=fff(fa[x]);
	return fa[x];
}

void init()
{
	int i,j;
	now=0;
	for(i=1;i<=n;i++)
	{
		l2[i]=1e9+7;
		r2[i]=0;
		edge[i].clear();
		v[i].clear();
		fa[i]=i;
	}
	memset(frt,0,(n+4)*sizeof(int));
	memset(chg,0,(n+4)*sizeof(int));
}

void dfs(int rt,int pa,int dis,int root)
{
	int i,j,uu,vv,dd;
	l1[rt]=++now+1;
	frt[rt]=root;
	init_val[now]=dis;
	for(i=0;i<edge[rt].size();i++)
	{
		uu=edge[rt][i].u; vv=edge[rt][i].v; dd=edge[rt][i].d;
		if(vv==pa) 
		{
			chg[uu]=1;
			continue;
		}
		l2[uu]=min(l2[uu],now+1);
//		cout<<uu<<' '<<vv<<' '<<dd<<endl;
		dfs(vv,rt,dis+dd,root);
		r2[uu]=max(r2[uu],now);
	}
	r1[rt]=now;
}

int main()
{
//	freopen("数据//1007.in","r",stdin);
//	freopen("数据//1007my.out","w",stdout);
	int i,j,typ,a,b,cas=0,pa,pb;
	while(scanf("%d%d%d",&n,&m,&q)!=EOF)
	{
		init();
		for(i=1;i<=n;i++)
		{
			scanf("%d",&r[i]);
			r[i]=log2(r[i]);
		}
		for(i=1;i<=m;i++)
		{
			scanf("%d%d%d",&typ,&a,&b);
			if(typ==1)
			{
				v[a].push_back(b);
				v[b].push_back(a);
			}
			else
				fa[fff(a)]=fff(b);
		}
		for(i=1;i<=n;i++)
			for(j=0;j<v[i].size();j++)
				edge[fff(i)].push_back(Edge{i,fff(v[i][j]),r[i]-r[v[i][j]]});			
		for(i=1;i<=n;i++)
			if(fa[i]==i && frt[i]==0)
				dfs(i,-1,0,i);
		build(1,1,now);
//		for(i=1;i<=n;i++)
//			printf("%d %d - %d %d %d %d - %d
",frt[i],chg[i],l1[i],r1[i],l2[i],r2[i],init_val[i]);
		printf("Case #%d:
",++cas);
		while(q--)
		{
			scanf("%d%d%d",&typ,&a,&b);
			if(typ==1)
			{
				b=log2(b);
				pa=fff(a);
				if(chg[a])
				{
					if(l1[pa]-1<=r1[pa])
						update(1,1,now,l1[pa]-1,r1[pa],+r[a]-b);
					if(l2[a]<=r2[a])
						update(1,1,now,l2[a],r2[a],-(+r[a]-b));					
				}
				else
				{
					if(l2[a]<=r2[a])
						update(1,1,now,l2[a],r2[a],-r[a]+b);
				}
				r[a]=b;
			}
			else
			{
				pa=fff(a);
				double ans=1.0*query(1,1,now,l1[frt[pa]]-1,r1[frt[pa]])-query(1,1,now,l1[pa]-1,l1[pa]-1)+log2(b);
				printf("%.3lf
",ans*log(2));
			} 
		}
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/FxxL/p/7260031.html