[SDOI2016]游戏

Description

Alice 和 Bob 在玩一个游戏。
游戏在一棵有 n 个点的树上进行。最初,每个点上都只有一个数字,那个数字是 123456789123456789。
有时,Alice 会选择一条从 s 到 t 的路径,在这条路径上的每一个点上都添加一个数字。对于路径上的一个点 r,
若 r 与 s 的距离是 dis,那么 Alice 在点 r 上添加的数字是 a×dis+b。有时,Bob 会选择一条从 s 到 t 的路径。
他需要先从这条路径上选择一个点,再从那个点上选择一个数字。
Bob 选择的数字越小越好,但大量的数字让 Bob 眼花缭乱。Bob 需要你帮他找出他能够选择的最小的数字。

Input

第一行两个数字 n、m,表示树的点数和进行的操作数。
接下来 n−1 行,每行三个数字 u、v、w,表示树上有一条连接 u、v 的边,长度是 w。
接下来 m 行。每行第一个数字是 1 或 2。
若第一个数是 1,表示 Alice 进行操作,接下来四个数字 s、t、a、b。
若第一个数是 2,表示 Bob 进行操作,接下来四个数字 s、t。

Output

每当 Bob 进行操作,输出一行一个数,表示他能够选择的最小的数字

Sample Input

3 5
1 2 10
2 3 20
2 1 3
1 2 3 5 6
2 2 3
1 2 3 -5 -6
2 2 3

Sample Output

123456789123456789
6
-106

HINT

 n≤100000,m≤100000,∣a∣≤10000,0<=w,|b|<=10^9

对于A*dis+B,将它分成s->lca,lca->t

s->lca:

A*(d[s]-d[x])+B=-A*d[x]+A*d[s]+B

lca->t:

A*(d[s]+d[x]-2*d[lca])+B=A*d[x]+A*d[s]-2*A*d[lca]+B

在一条链上显然d[fa]<d[son],所以相当于把一个一次函数放入几个线段

查询就是求区间线段最小值

然后就是lichao线段树

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 using namespace std;
  7 typedef long long lol;
  8 struct Node
  9 {
 10   int next,to;
 11   lol dis;
 12 }edge[200001];
 13 struct Line
 14 {
 15   lol k,b;
 16   bool id;
 17 }tree[400001];
 18 lol ans,d[100001],val[400001],inf=123456789123456789;
 19 int num,head[100001],size[100001],fa[100001][21],dep[100001],son[100001],dfn[100001],cnt,id[100001],top[100001],n,m;
 20 void add(int u,int v,lol w)
 21 {
 22   num++;
 23   edge[num].next=head[u];
 24   head[u]=num;
 25   edge[num].to=v;
 26   edge[num].dis=w;
 27 }
 28 void dfs1(int x,int pa)
 29 {int i;
 30   size[x]=1;
 31   for (i=head[x];i;i=edge[i].next)
 32     {
 33       int v=edge[i].to;
 34       if (v==pa) continue;
 35       fa[v][0]=x;
 36       d[v]=d[x]+edge[i].dis;
 37       dep[v]=dep[x]+1;
 38       dfs1(v,x);
 39       size[x]+=size[v];
 40       if (size[v]>size[son[x]]) son[x]=v;
 41     }
 42 }
 43 void dfs2(int x,int pa,int tp)
 44 {int i;
 45   dfn[x]=++cnt;
 46   id[cnt]=x;
 47   top[x]=tp;
 48   if (son[x]) dfs2(son[x],x,tp);
 49   for (i=head[x];i;i=edge[i].next)
 50     {
 51       int v=edge[i].to;
 52       if (v==pa||v==son[x]) continue;
 53       dfs2(v,x,v);
 54     }
 55 }
 56 int lca(int x,int y)
 57 {
 58   while (top[x]!=top[y])
 59     {
 60       if (d[top[x]]<d[top[y]]) swap(x,y);
 61       x=fa[top[x]][0];
 62     }
 63   if (d[x]<d[y]) return x;
 64   else return y;
 65 }
 66 lol cal(Line a,lol x)
 67 {
 68   return a.k*x+a.b;
 69 }
 70 double cross(Line x,Line y)
 71 {
 72   return (x.b-y.b)/(1.0*(y.k-x.k));
 73 }
 74 void add_min(int rt,int l,int r,Line x)
 75 {
 76   if (!tree[rt].id)
 77     {
 78       tree[rt]=x;
 79       return;
 80     }
 81   lol f1=cal(x,d[id[l]]);lol f2=cal(tree[rt],d[id[l]]);
 82   lol f3=cal(x,d[id[r]]);lol f4=cal(tree[rt],d[id[r]]);
 83   if (f1>=f2&&f3>=f4) return;
 84   else
 85     if (f1<=f2&&f3<=f4)
 86       {tree[rt]=x;}
 87     else
 88       {
 89     double p=cross(tree[rt],x);
 90     int mid=(l+r)/2;
 91     if (f1<=f2)
 92       {
 93         if (p<=d[id[mid]]) add_min(rt<<1,l,mid,x);
 94         else add_min(rt<<1|1,mid+1,r,tree[rt]),tree[rt]=x;
 95       }
 96     else
 97       {
 98         if (p<=d[id[mid]]) add_min(rt<<1,l,mid,tree[rt]),tree[rt]=x;
 99         else add_min(rt<<1|1,mid+1,r,x);
100       }
101       }
102 }
103 void update(int rt,int l,int r,int L,int R,Line x)
104 {
105     val[rt]=min(val[rt],min(cal(x,d[id[L]]),cal(x,d[id[R]])));
106   if (l==L&&r==R)
107     {
108       add_min(rt,l,r,x);
109       return;
110     }
111   int mid=(l+r)/2;
112   if (R<=mid) update(rt<<1,l,mid,L,R,x);
113   else if (L>mid) update(rt<<1|1,mid+1,r,L,R,x);
114   else
115     {
116       update(rt<<1,l,mid,L,mid,x);
117       update(rt<<1|1,mid+1,r,mid+1,R,x);
118     }
119 }
120 void query(int rt,int l,int r,int L,int R)
121 {
122   if (tree[rt].id)
123     {
124       ans=min(ans,min(cal(tree[rt],d[id[L]]),cal(tree[rt],d[id[R]])));
125     }
126   if (l==L&&r==R)
127     {
128       ans=min(ans,val[rt]);
129       return;
130     }
131   int mid=(l+r)/2;
132   if (R<=mid) query(rt<<1,l,mid,L,R);
133   else if (L>mid) query(rt<<1|1,mid+1,r,L,R);
134   else
135     {
136       query(rt<<1,l,mid,L,mid);query(rt<<1|1,mid+1,r,mid+1,R);
137     }
138 }
139 void build(int rt,int l,int r)
140 {
141   val[rt]=inf;
142   if (l==r) return;
143   int mid=(l+r)/2;
144   build(rt*2,l,mid);
145   build(rt*2+1,mid+1,r);
146 }
147 int main()
148 {int i,u,v,j,opt,s,t,x,y;
149   lol w,A,B;
150   cin>>n>>m;
151   for (i=1;i<=n-1;i++)
152     {
153       scanf("%d%d%lld",&u,&v,&w);
154       add(u,v,w);add(v,u,w);
155     }
156   dfs1(1,0);
157   dfs2(1,0,1);
158   for (i=1;i<=20;i++)
159     {
160       for (j=1;j<=n;j++)
161     fa[j][i]=fa[fa[j][i-1]][i-1];
162     }
163   build(1,1,n);
164   for (i=1;i<=m;i++)
165     {
166       scanf("%d",&opt);
167       if (opt==1)
168     {
169       scanf("%d%d%lld%lld",&s,&t,&A,&B);
170       int z=lca(s,t);
171       x=s;y=t;
172       while (top[x]!=top[z])
173         {
174           update(1,1,n,dfn[top[x]],dfn[x],(Line){-A,B+A*d[s],1});
175           x=fa[top[x]][0];
176         }
177       update(1,1,n,dfn[z],dfn[x],(Line){-A,B+A*d[s],1});
178       while (top[y]!=top[z])
179         {
180           update(1,1,n,dfn[top[y]],dfn[y],(Line){A,B-2*A*d[z]+A*d[s],1});
181           y=fa[top[y]][0];
182         }
183       update(1,1,n,dfn[z],dfn[y],(Line){A,B-2*A*d[z]+A*d[s],1});
184     }
185       else
186     {
187       scanf("%d%d",&s,&t);
188       int z=lca(s,t);
189       x=s;y=t;ans=inf;
190       while (top[x]!=top[z])
191         {
192           query(1,1,n,dfn[top[x]],dfn[x]);
193           x=fa[top[x]][0];
194         }
195       query(1,1,n,dfn[z],dfn[x]);
196       while (top[y]!=top[z])
197         {
198           query(1,1,n,dfn[top[y]],dfn[y]);
199           y=fa[top[y]][0];
200         }
201       query(1,1,n,dfn[z],dfn[y]);
202       printf("%lld\n",ans);
203     }
204     }
205 }

 

posted @ 2018-01-22 08:56  Z-Y-Y-S  阅读(413)  评论(3编辑  收藏  举报