zoukankan      html  css  js  c++  java
  • Bzoj4515 [Sdoi2016]游戏

    Time Limit: 40 Sec  Memory Limit: 256 MB
    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

    Sample Output

    123456789123456789
    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
    ",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
    ",
    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
    ",res);
    193         }
    194     }
    195     return 0;
    196 }
  • 相关阅读:
    SHELL
    终端如何输出彩色字体
    BTree和B+Tree详解
    博客项目----小功能模块
    python的学习之旅---Mysql数据库
    Python的学习之旅———协程
    python的学习之旅---信号量 定时器
    python的学习之旅---回调机制
    Python的学习之旅———线程 事件
    centos安装redis
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6682797.html
Copyright © 2011-2022 走看看