数据结构(树链剖分,线段树):SDOI 2016 游戏
Posted 既然选择了远方,便只顾风雨兼程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构(树链剖分,线段树):SDOI 2016 游戏相关的知识,希望对你有一定的参考价值。
4515: [Sdoi2016]游戏
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 351 Solved: 157
[Submit][Status][Discuss]
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
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int maxn=100010; 6 const long long INF=123456789123456789LL; 7 int cnt,fir[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1]; 8 void addedge(int a,int b,int v){ 9 nxt[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;val[cnt]=v; 10 } 11 12 int ID[maxn],top[maxn],rID[maxn],tot,n,Q; 13 int sz[maxn],dep[maxn],fa[maxn],son[maxn]; 14 long long dis[maxn],Min[maxn<<2]; 15 16 void DFS(int x){ 17 sz[x]=1; 18 for(int i=fir[x];i;i=nxt[i]) 19 if(to[i]!=fa[x]){ 20 fa[to[i]]=x; 21 dep[to[i]]=dep[x]+1; 22 dis[to[i]]=dis[x]+val[i]; 23 DFS(to[i]); 24 sz[x]+=sz[to[i]]; 25 if(sz[son[x]]<sz[to[i]]) 26 son[x]=to[i]; 27 } 28 } 29 30 void DFS(int x,int tp){ 31 top[x]=tp; 32 ID[x]=++tot;rID[tot]=x; 33 if(son[x])DFS(son[x],tp); 34 for(int i=fir[x];i;i=nxt[i]) 35 if(to[i]!=fa[x]&&to[i]!=son[x]) 36 DFS(to[i],to[i]); 37 } 38 39 int Lca(int x,int y){ 40 while(top[x]!=top[y]){ 41 if(dep[top[x]]<dep[top[y]])swap(x,y); 42 x=fa[top[x]]; 43 } 44 return dep[x]<dep[y]?x:y; 45 } 46 47 void Build(int x,int l,int r){ 48 Min[x]=INF; 49 if(l==r)return; 50 int mid=(l+r)>>1; 51 Build(x<<1,l,mid); 52 Build(x<<1|1,mid+1,r); 53 } 54 55 struct Node{ 56 long long a,b; 57 Node(long long a_=0,long long b_=INF){ 58 a=a_;b=b_; 59 } 60 long long Val(int x){ 61 return a*dis[rID[x]]+b; 62 } 63 }T[maxn<<2]; 64 65 int CmP(int l,int r,Node x,Node y){ 66 if(x.Val(l)<=y.Val(l)&&x.Val(r)<=y.Val(r))return 1; 67 if(x.Val(l)>=y.Val(l)&&x.Val(r)>=y.Val(r))return -1; 68 return 0; 69 } 70 71 void Update(int x,int l,int r,int a,int b,Node p){ 72 if(l>b||r<a)return; 73 Min[x]=min(Min[x],min(p.Val(max(l,a)),p.Val(min(r,b)))); 74 int mid=(l+r)>>1; 75 if(l>=a&&r<=b){ 76 int tmp=CmP(l,r,p,T[x]); 77 if(tmp==1)T[x]=p; 78 if(tmp!=0)return;//这里可以不用判断l==r 79 80 tmp=CmP(l,mid,p,T[x]); 81 if(tmp!=1)Update(x<<1,l,mid,a,b,T[x]); 82 tmp=CmP(mid+1,r,p,T[x]); 83 if(tmp!=1)Update(x<<1|1,mid+1,r,a,b,T[x]); 84 } 85 Update(x<<1,l,mid,a,b,p); 86 Update(x<<1|1,mid+1,r,a,b,p); 87 } 88 89 void Modify(int x,int y,Node p){ 90 while(top[x]!=top[y]){ 91 Update(1,1,n,ID[top[x]],ID[x],p); 92 x=fa[top[x]]; 93 } 94 Update(1,1,n,ID[y],ID[x],p); 95 } 96 97 long long Query(int x,int l,int r,int a,int b){ 98 if(l>b||r<a)return INF; 99 if(l>=a&&r<=b)return Min[x]; 100 int mid=(l+r)>>1; 101 long long ret=min(T[x].Val(max(l,a)),T[x].Val(min(r,b))); 102 if(mid>=a)ret=min(ret,Query(x<<1,l,mid,a,b)); 103 if(mid<b)ret=min(ret,Query(x<<1|1,mid+1,r,a,b)); 104 return ret; 105 } 106 107 long long Solve(int x,int y){ 108 long long ret=INF; 109 while(top[x]!=top[y]){ 110 if(dep[top[x]]<dep[top[y]])swap(x,y); 111 ret=min(ret,Query(1,1,n,ID[top[x]],ID[x])); 112 x=fa[top[x]]; 113 } 114 if(dep[x]<dep[y])swap(x,y); 115 ret=min(ret,Query(1,1,n,ID[y],ID[x])); 116 return ret; 117 } 118 119 int main(){ 120 #ifndef ONLINE_JUDGE 121 freopen("menci_game.in","r",stdin); 122 freopen("menci_game.out","w",stdout); 123 #endif 124 scanf("%d%d",&n,&Q); 125 for(int i=1,u,v,w;i<n;i++){ 126 scanf("%d%d%d",&u,&v,&w); 127 addedge(u,v,w);addedge(v,u,w); 128 } 129 DFS(1); 130 DFS(1,1); 131 Build(1,1,n); 132 133 int type,s,t,lca; 134 long long a,b; 135 while(Q--){ 136 scanf("%d",&type); 137 if(type==1){ 138 scanf("%d%d%lld%lld",&s,&t,&a,&b); 139 lca=Lca(s,t); 140 Modify(s,lca,Node(-a,a*dis[s]+b)); 141 Modify(t,lca,Node(a,a*(dis[s]-2*dis[lca])+b)); 142 } 143 else{ 144 scanf("%d%d",&s,&t); 145 printf("%lld\n",Solve(s,t)); 146 } 147 } 148 return 0; 149 }
以上是关于数据结构(树链剖分,线段树):SDOI 2016 游戏的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 3531 [Sdoi2014]旅行(树链剖分,线段树)
BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并