Bzoj4515 [Sdoi2016]游戏
Submit: 594 Solved: 234
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
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
6
-106
HINT
n≤100000,m≤100000,∣a∣≤10000,0<=w,|b|<=10^9
Source
树链剖分+李超线段树
似乎是传说中的线段树维护半平面交。
在从s到t的路径上的每一个点上都添加一个值,添加的值满足某个函数关系;
询问从s到t的路径上最小的值。
如果把从s到t的路径从树上拎出来,那就得到了一条链,这条链可以看作是以s为原点的数轴,在数轴上脑补一个平面直角坐标系,我们要做的其实是往坐标系中添加线段,并查询某个横坐标x对应的最小的线段纵坐标f(x)。
拎一条链出来,当然就是树链剖分了。
接下来在线段树上维护线段(好像略喜感)。在线段树的每个结点上,存长度大于该结点对应区间的最优的线段。
当更新区间的时候,如果新线段完全比结点上存的旧线段优或者劣,就可以替换/舍弃。但如果只是一部分比旧线段优,就应该把占优比例更多的那条留在当前结点,把另一条下传到子区间递归更新。
询问的时候,由于每一层都存有线段,在每一层都需要更新。
我的线段树写法是(L<=l && r<=R)时更新,结点最小值取min(F(L),F(R)),在这个问题中,显然如果线段的左右端点在l和L之间,这样更新会记录下实际不属于该结点对应区间的值。
解决办法是最小值取min (F(max(L,l)),F(min(r,R)) )
而我并没有意识到这个显然的问题,加上另一些细节问题,WA记录成功刷了半页
CGOS提供数据真是良心
肝了差不多两晚上才切掉,终于可以安心刷会儿邦邦了
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 #define LL long long 7 using namespace std; 8 const LL INF =123456789123456789LL; 9 const int mxn=200010; 10 LL read(){ 11 LL x=0,f=1;char ch=getchar(); 12 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 void write(LL x){ 17 if(x>9)write(x/10); 18 putchar(x%10+'0'); 19 return; 20 } 21 // 22 struct edge{ 23 int v,nxt,w; 24 }e[mxn<<1]; 25 int hd[mxn],mct=0; 26 void add_edge(int u,int v,int w){ 27 e[++mct].v=v;e[mct].nxt=hd[u];e[mct].w=w;hd[u]=mct;return; 28 } 29 // 30 struct node{ 31 int fa,son,top; 32 int w,e; 33 }t[mxn]; 34 int sz[mxn],dep[mxn],tct=0; 35 int mp[mxn]; 36 LL dis[mxn]; 37 void DFS1(int u,int fa){ 38 sz[u]=1; 39 dep[u]=dep[fa]+1; 40 for(int i=hd[u],v;i;i=e[i].nxt){ 41 v=e[i].v; 42 if(v==fa)continue; 43 t[v].fa=u; 44 dis[v]=dis[u]+e[i].w; 45 DFS1(v,u); 46 sz[u]+=sz[v]; 47 if(sz[v]>sz[t[u].son])t[u].son=v; 48 } 49 return; 50 } 51 void DFS2(int u,int top){ 52 // printf("dfs:%u\n",u); 53 t[u].w=++tct; 54 t[u].top=top; 55 mp[tct]=u;//反向映射 56 if(t[u].son){ 57 DFS2(t[u].son,top); 58 for(int i=hd[u],v;i;i=e[i].nxt){ 59 v=e[i].v; 60 if(v==t[u].fa || v==t[u].son)continue; 61 DFS2(v,v); 62 } 63 } 64 t[u].e=tct; 65 return; 66 } 67 int LCA(int x,int y){ 68 while(t[x].top!=t[y].top){ 69 if(dep[t[x].top]<dep[t[y].top])swap(x,y); 70 x=t[t[x].top].fa; 71 } 72 return dep[x]<dep[y]?x:y; 73 } 74 // 75 struct SGT{ 76 int l,r; 77 LL a,b,mini; 78 }st[mxn<<2]; 79 int cnt=0,rot; 80 int n,m; 81 inline LL F(LL a,LL b,int x){ 82 return a*dis[mp[x]]+b; 83 } 84 inline void pushup(int rt){ 85 st[rt].mini=min(st[rt].mini,min(st[st[rt].l].mini,st[st[rt].r].mini)); 86 return; 87 } 88 void Build(int l,int r,int &rt){ 89 if(!rt)rt=++cnt; 90 st[rt].a=0; 91 st[rt].b=st[rt].mini=INF; 92 if(l==r)return; 93 int mid=(l+r)>>1; 94 Build(l,mid,st[rt].l); 95 Build(mid+1,r,st[rt].r); 96 // pushup(rt); 97 return; 98 } 99 100 void modify(LL a,LL b,int l,int r,int rt){ 101 LL fL=F(st[rt].a,st[rt].b,l); LL fR=F(st[rt].a,st[rt].b,r); 102 LL nL=F(a,b,l); LL nR=F(a,b,r); 103 if(fL>=nL && fR>=nR){//完全更优 104 st[rt].a=a;st[rt].b=b;return; 105 } 106 if(fL<=nL && fR<=nR)return;//完全更差 107 int mid=(l+r)>>1; 108 LL fM=F(st[rt].a,st[rt].b,mid); 109 LL nM=F(a,b,mid); 110 if(fM>nM){ 111 swap(st[rt].a,a);swap(st[rt].b,b); 112 swap(fL,nL);swap(fR,nR); 113 } 114 if(fL>=nL)modify(a,b,l,mid,st[rt].l); 115 if(fR>=nR)modify(a,b,mid+1,r,st[rt].r); 116 // pushup(rt); 117 return; 118 } 119 void update(LL a,LL b,int L,int R,int l,int r,int rt){ 120 st[rt].mini=min(st[rt].mini,min(F(a,b,max(L,l)),F(a,b,min(r,R))));//取正确端点 121 if(L<=l && r<=R){ 122 modify(a,b,l,r,rt); 123 return; 124 } 125 int mid=(l+r)>>1; 126 if(L<=mid)update(a,b,L,R,l,mid,st[rt].l); 127 if(R>mid)update(a,b,L,R,mid+1,r,st[rt].r); 128 // pushup(rt); 129 return; 130 } 131 LL query(int L,int R,int l,int r,int rt){ 132 // printf("%lld %lld %lld L:%d R:%d l:%d r:%d rt:%d\n", 133 // st[rt].a,st[rt].b,st[rt].mini,L,R,l,r,rt); 134 LL res=INF; 135 res=min(F(st[rt].a,st[rt].b,max(L,l)),F(st[rt].a,st[rt].b,min(r,R))); 136 if(L<=l && r<=R){ 137 res=min(res,st[rt].mini); 138 return res; 139 } 140 int mid=(l+r)>>1; 141 if(L<=mid)res=min(res,query(L,R,l,mid,st[rt].l)); 142 if(R>mid)res=min(res,query(L,R,mid+1,r,st[rt].r)); 143 return res; 144 } 145 void T_add(int x,int y,LL a,LL b){ 146 while(t[x].top!=t[y].top){ 147 if(dep[t[x].top]<dep[t[y].top])swap(x,y); 148 update(a,b,t[t[x].top].w,t[x].w,1,n,rot); 149 x=t[t[x].top].fa; 150 } 151 if(dep[x]>dep[y])swap(x,y); 152 update(a,b,t[x].w,t[y].w,1,n,rot); 153 return; 154 } 155 LL Que(int x,int y){ 156 LL res=INF; 157 while(t[x].top!=t[y].top){ 158 if(dep[t[x].top]<dep[t[y].top])swap(x,y); 159 res=min(res,query(t[t[x].top].w,t[x].w,1,n,rot)); 160 x=t[t[x].top].fa; 161 } 162 if(dep[x]>dep[y])swap(x,y); 163 res=min(res,query(t[x].w,t[y].w,1,n,rot)); 164 return res; 165 } 166 int main(){ 167 // freopen("menci_game.in","r",stdin); 168 // freopen("menci_game.out","w",stdout); 169 int i,j,u,v,w; 170 n=read();m=read(); 171 for(i=1;i<n;i++){ 172 u=read();v=read();w=read(); 173 add_edge(u,v,w); 174 add_edge(v,u,w); 175 } 176 DFS1(1,0); 177 DFS2(1,1); 178 Build(1,n,rot); 179 int op,s,t; 180 LL a,b; 181 for(i=1;i<=m;i++){ 182 op=read(); 183 if(op==1){ 184 s=read();t=read();a=read();b=read(); 185 int tmp=LCA(s,t); 186 T_add(s,tmp,-a,a*dis[s]+b); 187 T_add(tmp,t,a,a*(dis[s]-dis[tmp]*2)+b); 188 } 189 else{ 190 s=read();t=read(); 191 LL res=Que(s,t); 192 printf("%lld\n",res); 193 } 194 } 195 return 0; 196 }
本文为博主原创文章,转载请注明出处。