hdu6039 Gear Up-线段树
来源:互联网 发布:伦纳德官方体测数据 编辑:程序博客网 时间:2024/06/15 11:59
题意:
给出n个齿轮的半径和n个齿轮之间的关系(角速度相等或线速度相等),两种操作,第一种操作:修改一个齿轮的半径,第二种操作:给一个齿轮角速度,输出最大的角速度,答案取ln(自然对数)。
Solution:
我们随意画一个图感受一下:
(粗边表示角速度相等,细边表示线速度相等,图中维护的是每个点的角速度和
我们可以发现一个规律:如果修改的点的父亲边是线边,那么到他线边所连的儿子的值是不包含这个点的半径的,也就是说,修改这个点的半径不会影响这个点线边所连的儿子,只会影响角边所连的儿子及儿子所在的子树;如果修改的点的父亲边是角边,那么只会影响这个点线边所连的儿子及儿子所在的子树,不影响这个点角边所连的儿子。
归纳一下:
修改一个点的半径r->r’,如果修改的点的父亲边是线边,那么角边所连的儿子及儿子所在的子树
那么这道题就可以用线段树搞了,求出这棵树的dfs序,维护区间乘,区间取max即可,因为这道题要求取自然对数,所以我们可以维护ln值,就可以把区间乘转化为区间加了。
代码:
#include<cstdio>#include<iostream>#include<cstring>#include<cmath>using namespace std;const int N=100010;int n,m;int size,head[N];struct edg{ int from,to,next; double v;}g[2*N],e[2*N];int f[N];int q;int h[N],l[N],r[N],ll[N],rr[N];double ra[N];int fa[N];int T,x,y,a,rt[N],cnt;double v[N];bool p[N];struct tree{ int l,r; double tag,maxn;}tr[4*N];void update(int i){ tr[i].maxn=max(tr[i<<1].maxn,tr[i<<1|1].maxn); return;}void build(int i,int l,int r){ tr[i].l=l;tr[i].r=r; tr[i].maxn=0;tr[i].tag=0; if (l==r) {tr[i].maxn=v[l];return;} int mid=(l+r)>>1; build(i<<1,l,mid); build(i<<1|1,mid+1,r); update(i);}void addtag(int i,double x){ tr[i].tag+=x; tr[i].maxn+=x;}void pushdown(int i){ if (tr[i].tag) { if (tr[i].l==tr[i].r) return; addtag(i<<1,tr[i].tag); addtag(i<<1|1,tr[i].tag); tr[i].tag=0; }}void modify(int i,int l,int r,double x){ int L=tr[i].l,R=tr[i].r; if (l>R||r<L) return; if (l<=L&&R<=r) {addtag(i,x);return;} pushdown(i); modify(i<<1,l,r,x); modify(i<<1|1,l,r,x); update(i);}double query(int i,int l,int r){ int L=tr[i].l,R=tr[i].r; if (l>R||r<L) return -1e9; if (l<=L&&R<=r) return tr[i].maxn; pushdown(i); double ans=-1e9; ans=max(ans,query(i<<1,l,r)); ans=max(ans,query(i<<1|1,l,r)); return ans;}int find(int x){ if (fa[x]!=x) fa[x]=find(fa[x]); return fa[x];}void add(int x,int y){ size++; e[size].to=y; e[size].next=head[x]; head[x]=size;}void ad(int x,int y,int f,double v){ size++; g[size].to=y; g[size].v=v; g[size].from=f; g[size].next=h[x]; h[x]=size;}void dfs(int root,int fa,int x,double dis){ rt[x]=root; l[x]=++cnt; v[cnt]=dis; for (int i=h[x];i;i=g[i].next) { int y=g[i].to; int xx=g[i].from; if (y!=fa) { ll[xx]=min(ll[xx],cnt+1); dfs(root,x,y,1.0*dis+g[i].v); rr[xx]=max(rr[xx],cnt); } else p[xx]=1; } r[x]=cnt;}int main(){ while (scanf("%d%d%d",&n,&m,&q)!=EOF) { memset(p,0,sizeof(p)); memset(h,0,sizeof(h)); memset(head,0,sizeof(head)); memset(rt,0,sizeof(rt)); for (int i=1;i<=n;i++) scanf("%lf",&ra[i]),ra[i]=log(ra[i]),fa[i]=i; size=0; for (int i=1;i<=m;i++) { scanf("%d%d%d",&a,&x,&y); if (a==1) add(x,y),add(y,x); else x=find(x),y=find(y),fa[x]=y; } size=0; for (int i=1;i<=n;i++) { ll[i]=1e9,rr[i]=0; for (int j=head[i];j;j=e[j].next) { int x=e[j].to; ad(find(i),find(x),i,ra[i]-ra[x]); } } cnt=0; for (int i=1;i<=n;i++)if (find(i)==i&&!rt[i]) dfs(i,0,i,0.0); build(1,1,cnt); printf("Case #%d:\n",++T); for (int i=1;i<=q;i++) { scanf("%d%d%d",&a,&x,&y); double yy=log(y); if (a==1) { if (p[x]) modify(1,l[find(x)],r[find(x)],-yy+ra[x]); if (ll[x]<=rr[x]) modify(1,ll[x],rr[x],yy-ra[x]); ra[x]=yy; } else { printf("%.3f\n",yy-query(1,l[find(x)],l[find(x)])+query(1,l[rt[find(x)]],r[rt[find(x)]])); } } }}
阅读全文