zoukankan      html  css  js  c++  java
  • [loj574]黄金矿工

    记$dep_{x}$为1到$x$的边权和,当$x$上的矿工挖了$y$上的黄金时($y$在$x$子树内),显然$sum_{e}c_{e}=dep_{y}-dep_{x}$

    由此,对于$u$上权值为$v$的矿工(或黄金),不妨修改其权值为$v-dep_{x}$(或$v+dep_{x}$)

    此时,矿工挖黄金的收益即两者的权值和(同时黄金要在矿工子树内),因此我们仅关心于挖了黄金的矿工和被挖的黄金,而不关心具体谁挖了谁

    根据Hall定理,当选择了若干个黄金和矿工后,判断是否合法仅需要保证:

    1.选择的矿工数等于黄金数

    2.令$Delta_{i}$表示$i$子树内选择的黄金数量-矿工的数量,要求$forall 1le ile n,Delta_{i}ge 0$

    一个技巧:在选择$u$上一个权值为$v$的矿工(或黄金)时,直接将该矿工(或黄金)删除,并在$u$上增加一个权值为$-v$的黄金(或矿工),即可用选择来代替撤销,因此以下不考虑撤销的操作

    由于一个节点上会有多个矿工和黄金,对两者分别维护一个set(可重),并只需要将set中的最大值作为”该点上的矿工(或黄金)“即可

    下面,对加入矿工和加入黄金的操作分别讨论:

    1.当在$u$上插入一个权值为$v$的矿工,不妨先选择这个矿工,为了保持数量一致,即需要再选择一个黄金

    (由于本来的方案是最优的,显然对其他矿工或黄金调整都会与此矛盾)

    很显然,只需要对$u$到根路径上所有$Delta_{i}$减少1,并找到其中第一个(最深的)$i$满足$Delta_{i}=-1$,在$i$的子树内选择权值最大的黄金即可

    用树链剖分+线段树维护$Delta_{i}$,用线段树维护子树内权值最大的黄金,复杂度为$o(log^{2}n)$

    2.当在$u$上插入一个权值为$v$的黄金,同理先选择这个黄金,然后再选择一个矿工

    考虑在每一个节点$u$上,用set维护$u$轻儿子子树内或$v=u$的节点$v$上矿工的权值,满足$v$到$u$路径上$Delta_{i}ge 1$,并用树链剖分+线段树维护这个set的最大值

    考虑维护,即对每一条重链,将重链合法的前缀(即找到最浅的$Delta_{i}$满足$Delta_{i}le 0$,从$i$的父亲到重链顶端)中(set的最大值)的最大值加入到重链顶端节点的父亲节点上

    考虑维护,在每一次$x$上的权值或$x$到根的$Delta$时,就将$x$到根路径上$x$的影响全部删除,修改后再加入(并且也不一定要判定是$x$的影响)

    总复杂度为$o(nlog^{2}n)$,可以通过

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 100005
      4 #define oo 0x3f3f3f3f
      5 #define ll long long
      6 #define pii pair<int,int>
      7 #define L (k<<1)
      8 #define R (L+1)
      9 #define mid (l+r>>1)
     10 struct Edge{
     11     int nex,to,len;
     12 }edge[N<<1];
     13 multiset<int>s[2][N];
     14 multiset<pair<int,int> >S[N];
     15 pair<int,int>mxf[2][N<<2];
     16 int E,n,m,p,x,y,z,head[N],fa[N],sz[N],dep[N],mx[N],dfn[N],idfn[N],top[N],leaf[N];
     17 int tag[N<<2],mnf[N<<2];
     18 ll ans;
     19 void upd(int k,int x){
     20     tag[k]+=x;
     21     mnf[k]+=x;
     22 }
     23 void down(int k){
     24     upd(L,tag[k]);
     25     upd(R,tag[k]);
     26     tag[k]=0;
     27 }
     28 void build(int k,int l,int r){
     29     mxf[0][k]=mxf[1][k]=make_pair(-oo,0);
     30     if (l==r)return;
     31     build(L,l,mid);
     32     build(R,mid+1,r);
     33 }
     34 void update_Delta(int k,int l,int r,int x,int y,int z){
     35     if ((l>y)||(x>r))return;
     36     if ((x<=l)&&(r<=y)){
     37         upd(k,z);
     38         return;
     39     }
     40     down(k);
     41     update_Delta(L,l,mid,x,y,z);
     42     update_Delta(R,mid+1,r,x,y,z);
     43     mnf[k]=min(mnf[L],mnf[R]);
     44 }
     45 void update_val(int p,int k,int l,int r,int x,pii y){
     46     if (l==r){
     47         mxf[p][k]=y;
     48         return;
     49     }
     50     if (x<=mid)update_val(p,L,l,mid,x,y);
     51     else update_val(p,R,mid+1,r,x,y);
     52     mxf[p][k]=max(mxf[p][L],mxf[p][R]);
     53 }
     54 int query_first(int k,int l,int r,int x,int y){
     55     if ((l>y)||(x>r)||(mnf[k]>=1))return 0;
     56     if (l==r)return l;
     57     down(k);
     58     int ans=query_first(L,l,mid,x,y);
     59     if (ans)return ans;
     60     return query_first(R,mid+1,r,x,y);
     61 }
     62 int query_last(int k,int l,int r,int x,int y){
     63     if ((l>y)||(x>r)||(mnf[k]>=0))return 0;
     64     if (l==r)return l;
     65     down(k);
     66     int ans=query_last(R,mid+1,r,x,y);
     67     if (ans)return ans;
     68     return query_last(L,l,mid,x,y);
     69 }
     70 pii query_max(int p,int k,int l,int r,int x,int y){
     71     if ((l>y)||(x>r))return make_pair(-oo,0);
     72     if ((x<=l)&&(r<=y))return mxf[p][k];
     73     return max(query_max(p,L,l,mid,x,y),query_max(p,R,mid+1,r,x,y));
     74 }
     75 void update_Delta(int k,int p){
     76     while (k){
     77         update_Delta(1,1,n,dfn[top[k]],dfn[k],p);
     78         k=fa[top[k]];
     79     }
     80 }
     81 pii get(int k){
     82     if (S[k].empty())return make_pair(-oo,0);
     83     return (*--S[k].end());
     84 }
     85 pii calc(int k){
     86     int pos=query_first(1,1,n,dfn[k],dfn[leaf[k]]);
     87     if (!pos)pos=dfn[leaf[k]]+1;
     88     return query_max(0,1,1,n,dfn[k],pos-1);
     89 }
     90 void add_val(int k){
     91     while (k){
     92         update_val(0,1,1,n,dfn[k],get(k));
     93         pii o=calc(top[k]);
     94         if (fa[top[k]])S[fa[top[k]]].insert(o);
     95         k=fa[top[k]];
     96     }
     97 }
     98 void del_val(int k){
     99     while (k){
    100         pii o=calc(top[k]);
    101         if (fa[top[k]])S[fa[top[k]]].erase(S[fa[top[k]]].find(o));
    102         update_val(0,1,1,n,dfn[k],make_pair(-oo,0));
    103         k=fa[top[k]];
    104     }
    105 }
    106 int get(int p,int x){
    107     if (s[p][x].empty())return -oo;
    108     return (*--s[p][x].end());
    109 }
    110 void add(int p,int x,int y){
    111     if (!p)del_val(x);
    112     s[p][x].insert(y);
    113     if (p)update_val(1,1,1,n,dfn[x],make_pair(get(p,x),x));
    114     else{
    115         S[x].insert(make_pair(y,x));
    116         add_val(x);
    117     }
    118 }
    119 void choose(int p,int x){
    120     if (!p)del_val(x);
    121     int y=get(p,x);
    122     ans+=y;
    123     s[p][x].erase(s[p][x].find(y));
    124     if (p)update_val(1,1,1,n,dfn[x],make_pair(get(p,x),x));
    125     else S[x].erase(S[x].find(make_pair(y,x)));
    126     add(p^1,x,-y);
    127     if (!p)update_Delta(x,-1);
    128     else{
    129         del_val(x);
    130         update_Delta(x,1);
    131         add_val(x);
    132     }
    133     if (!p)add_val(x);
    134 }
    135 void Add0(int x,int y){
    136     add(0,x,y);
    137     if (get(0,x)!=y)return;
    138     choose(0,x);
    139     while (x){
    140         int pos=query_last(1,1,n,dfn[top[x]],dfn[x]);
    141         if (pos){
    142             pos=idfn[pos];
    143             choose(1,query_max(1,1,1,n,dfn[pos],dfn[pos]+sz[pos]-1).second);
    144             return;
    145         }
    146         x=fa[top[x]];
    147     }
    148 }
    149 void Add1(int x,int y){
    150     add(1,x,y);
    151     if (get(1,x)!=y)return;
    152     choose(1,x);
    153     choose(0,calc(1).second);
    154 }
    155 void add_edge(int x,int y,int z){
    156     edge[E].nex=head[x];
    157     edge[E].to=y;
    158     edge[E].len=z;
    159     head[x]=E++;
    160 }
    161 void dfs1(int k,int f,int sh){
    162     fa[k]=f;
    163     sz[k]=1;
    164     dep[k]=sh;
    165     for(int i=head[k];i!=-1;i=edge[i].nex)
    166         if (edge[i].to!=f){
    167             dfs1(edge[i].to,k,sh+edge[i].len);
    168             sz[k]+=sz[edge[i].to];
    169             if (sz[mx[k]]<sz[edge[i].to])mx[k]=edge[i].to;
    170         }
    171 }
    172 void dfs2(int k,int fa,int t){
    173     dfn[k]=++dfn[0];
    174     idfn[dfn[0]]=k;
    175     top[k]=t;
    176     if (!mx[k])leaf[k]=k;
    177     else{
    178         dfs2(mx[k],k,t);
    179         leaf[k]=leaf[mx[k]];
    180     }
    181     for(int i=head[k];i!=-1;i=edge[i].nex)
    182         if ((edge[i].to!=fa)&&(edge[i].to!=mx[k]))dfs2(edge[i].to,k,edge[i].to);
    183 }
    184 int main(){
    185     scanf("%d%d",&n,&m);
    186     memset(head,-1,sizeof(head));
    187     for(int i=1;i<n;i++){
    188         scanf("%d%d%d",&x,&y,&z);
    189         add_edge(x,y,z);
    190         add_edge(y,x,z);
    191     }
    192     dfs1(1,0,0);
    193     dfs2(1,0,1);
    194     build(1,1,n);
    195     for(int i=2;i<=n;i++)
    196         if (top[i]==i)S[fa[i]].insert(make_pair(-oo,0));
    197     for(int i=1;i<=m;i++){
    198         scanf("%d%d%d",&p,&x,&y);
    199         if (p==1){
    200             y-=dep[x];
    201             Add0(x,y);
    202         }
    203         if (p==2){
    204             y+=dep[x];
    205             Add1(x,y);
    206         }
    207         printf("%lld
    ",ans);
    208     } 
    209 } 
    View Code
  • 相关阅读:
    C# -- HttpWebRequest 和 HttpWebResponse 的使用
    C# -- Lambda 表达式的使用
    ASP.NET -- WebForm -- HttpRequest类的方法和属性
    ASP.NET -- WebForm -- HttpResponse 类的方法和属性
    C# -- 索引器、枚举类型
    C#设计模式之七桥接模式(Bridge Pattern)【结构型】
    C#设计模式之六适配器模式(Adapter Pattern)【结构型】
    C#设计模式之五原型模式(Prototype Pattern)【创建型】
    C#设计模式之四建造者模式(Builder Pattern)【创建型】
    C#设计模式之三抽象工厂模式(AbstractFactory)【创建型】
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14863123.html
Copyright © 2011-2022 走看看