zoukankan      html  css  js  c++  java
  • UOJ268 [清华集训2016] 数据交互 【动态DP】【堆】【树链剖分】【线段树】

    题目分析:

    不难发现可以用动态DP做。

    题目相当于是要我求一条路径,所有与路径有交的链的代价加入进去,要求代价最大。

    我们把链的代价分成两个部分:一部分将代价加入$LCA$之中,用$g$数组保存;另一部分将代价加在整条链上,用$d$数组保存。

    这时候我们可以发现,一条从$u$到$v$的路径的代价相当于是$d[LCA(u,v)]+sum_{x in edge(u,v)}g[x]$。

    如果是静态的,可以用树形DP解决。

    看过《神奇的子图》的同学都知道,叶子结点是从它的儿子中取两个最大的出来,所以堆维护。

    考虑合并。

    链从左延申出的最大的$g$的总和记录。链从右延申包括$d$的总和记录,每次向上$update$的时候拼起来与原答案比较即可。

    代码:

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 
      4 typedef long long ll;
      5 
      6 const int maxn = 102000;
      7 
      8 int n,m;
      9 
     10 vector <int> g[maxn];
     11 int sz[maxn],top[maxn],fa[maxn],dep[maxn],son[maxn],ind[maxn],dr[maxn];
     12 int tail[maxn],num;
     13 
     14 struct Query{int from,to,w;}Q[maxn];
     15 struct Priority_Queue{
     16     priority_queue<ll,vector<ll>,less<ll> > pq,del;
     17     void push(ll now){pq.push(now);}
     18     void pop(){
     19     while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
     20     pq.pop();
     21     }
     22     ll top(){
     23     while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
     24     if(pq.empty()) return 0;
     25     else return pq.top();
     26     }
     27     ll sec(){
     28     while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
     29     if(pq.size() ==0) return 0;
     30     ll oop = pq.top(); pq.pop();
     31     while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
     32     if(pq.size() == 0){pq.push(oop);return 0;}
     33     else {ll ret = pq.top();pq.push(oop);return ret;}
     34     }
     35     void Erase(ll now){del.push(now);}
     36 }Son[maxn],Ans;
     37 
     38 struct segmentTree{
     39     ll tg,ff,lazy,REC,L,R;
     40 }T[maxn<<2];
     41 
     42 void push_down(int now){
     43     T[now<<1].ff += T[now].lazy; T[now<<1|1].ff += T[now].lazy;
     44     T[now<<1].REC += T[now].lazy; T[now<<1|1].REC += T[now].lazy;
     45     T[now<<1].lazy += T[now].lazy; T[now<<1|1].lazy += T[now].lazy;
     46     T[now<<1].R += T[now].lazy; T[now<<1|1].R += T[now].lazy;
     47     T[now].lazy = 0;
     48 }
     49 
     50 segmentTree merge(segmentTree alpha,segmentTree beta){
     51     segmentTree RES;RES.lazy = 0;  RES.ff = 0;
     52     RES.tg = alpha.tg + beta.tg;
     53     RES.REC = max(alpha.REC,beta.REC);
     54     RES.REC = max(RES.REC,alpha.R + beta.L);
     55     RES.L = max(alpha.L,alpha.tg + beta.L);
     56     RES.R = max(beta.R,alpha.R + beta.tg);
     57     return RES;
     58 }
     59 
     60 void dfs1(int now,int f,int dp){
     61     dep[now] = dp; fa[now] = f;
     62     int maxx = 0;
     63     for(auto it:g[now]){
     64     if(it == f) continue;
     65     dfs1(it,now,dp+1);
     66     sz[now] += sz[it];
     67     if(maxx == 0 || sz[it] > sz[maxx]) maxx = it;
     68     }
     69     son[now] = maxx; sz[now]++;
     70 }
     71 
     72 void dfs2(int now,int tp){
     73     top[now] = tp; ind[now] = ++num; dr[num] = now;
     74     if(now == tp) Ans.push(0);
     75     if(son[now]) dfs2(son[now],tp);
     76     else tail[tp] = now;
     77     for(auto it : g[now]){
     78     if(it == fa[now] || it == son[now]) continue;
     79     dfs2(it,it);
     80     }
     81 }
     82 
     83 void read(){
     84     scanf("%d%d",&n,&m);
     85     for(int i=1;i<n;i++){
     86     int u,v; scanf("%d%d",&u,&v);
     87     g[u].push_back(v); g[v].push_back(u);
     88     }
     89 }
     90 
     91 int QueryLca(int u,int v){
     92     while(top[u] != top[v]){
     93     if(dep[top[u]] > dep[top[v]]) u = fa[top[u]];
     94     else v = fa[top[v]];
     95     }
     96     if(dep[u] < dep[v]) return u; else return v;
     97 }
     98 
     99 segmentTree Querylen(int now,int tl,int tr,int l,int r){
    100     if(tl >= l && tr <= r) return T[now];
    101     if(T[now].lazy) push_down(now);
    102     int mid = (tl+tr)/2;
    103     if(mid < l) return Querylen(now<<1|1,mid+1,tr,l,r);
    104     if(mid >= r) return Querylen(now<<1,tl,mid,l,r);
    105     segmentTree pp = Querylen(now<<1|1,mid+1,tr,l,r);
    106     segmentTree qq = Querylen(now<<1,tl,mid,l,r);
    107     return merge(qq,pp);
    108 }
    109 
    110 void AddG(int now,int tl,int tr,int place,int w){
    111     if(tl == tr){T[now].tg += w;T[now].L += w;return;}
    112     if(T[now].lazy) push_down(now);
    113     int mid = (tl+tr)/2;
    114     if(mid >= place) AddG(now<<1,tl,mid,place,w);
    115     else AddG(now<<1|1,mid+1,tr,place,w);
    116     T[now] = merge(T[now<<1],T[now<<1|1]);
    117 }
    118 
    119 void ModifyG(int now,int tl,int tr,int place){
    120     if(tl == tr){
    121     tl = dr[tl]; T[now].L = Son[tl].top() + T[now].tg;
    122     T[now].REC = T[now].ff + Son[tl].top() + Son[tl].sec();
    123     T[now].R = T[now].ff + Son[tl].top();
    124     return;
    125     }
    126     if(T[now].lazy) push_down(now);
    127     int mid = (tl+tr)/2;
    128     if(mid >= place) ModifyG(now<<1,tl,mid,place);
    129     else ModifyG(now<<1|1,mid+1,tr,place);
    130     T[now] = merge(T[now<<1],T[now<<1|1]);
    131 }
    132 
    133 void ModifyF(int now,int tl,int tr,int l,int r,int w){
    134     if(tl >= l && tr <= r){
    135     T[now].lazy += w; T[now].ff += w; T[now].R += w; T[now].REC+=w;
    136     return;
    137     }
    138     if(T[now].lazy) push_down(now);
    139     int mid = (tl+tr)/2;
    140     if(mid >= l) ModifyF(now<<1,tl,mid,l,r,w);
    141     if(mid+1 <= r) ModifyF(now<<1|1,mid+1,tr,l,r,w);
    142     T[now] = merge(T[now<<1],T[now<<1|1]);
    143 }
    144 
    145 void SingleModify(int now,int w){
    146     int hole = tail[top[now]]; 
    147     segmentTree fk = Querylen(1,1,n,ind[top[hole]],ind[hole]);
    148     AddG(1,1,n,ind[now],w); now=fa[top[now]];
    149     while(now){
    150     segmentTree rl = Querylen(1,1,n,ind[top[hole]],ind[hole]);
    151     Ans.Erase(fk.REC); Ans.push(rl.REC);
    152     Son[now].Erase(fk.L); Son[now].push(rl.L);
    153     hole = tail[top[now]]; fk = Querylen(1,1,n,ind[top[hole]],ind[hole]);
    154     ModifyG(1,1,n,ind[now]); now = fa[top[now]];
    155     }
    156     Ans.Erase(fk.REC);
    157     fk = Querylen(1,1,n,ind[top[hole]],ind[hole]);
    158     Ans.push(fk.REC);
    159 }
    160 
    161 void WideModify(int now,int LCA,int w){
    162     while(dep[now] >= dep[LCA]){
    163     segmentTree fk = Querylen(1,1,n,ind[top[now]],ind[tail[top[now]]]);
    164     if(dep[top[now]] < dep[LCA]) ModifyF(1,1,n,ind[LCA],ind[now],w);
    165     else ModifyF(1,1,n,ind[top[now]],ind[now],w);
    166     Ans.Erase(fk.REC);
    167     fk = Querylen(1,1,n,ind[top[now]],ind[tail[top[now]]]);
    168     Ans.push(fk.REC);
    169     now = fa[top[now]];
    170     }
    171 }
    172 
    173 void Modify(int u,int v,int w){
    174     int LCA = QueryLca(u,v);
    175     SingleModify(LCA,w);
    176     WideModify(u,LCA,w); // u
    177     WideModify(v,LCA,w); // v
    178     WideModify(LCA,LCA,-w); // LCA
    179 }
    180 
    181 void build_tree(int now,int tl,int tr){
    182     if(tl == tr){
    183     tl = dr[tl];
    184     for(auto it : g[tl]){
    185         if(it == son[tl] || it == fa[tl]) continue;
    186         Son[tl].push(0);
    187     }
    188     }else{
    189     int mid = (tl+tr)/2;
    190     build_tree(now<<1,tl,mid); build_tree(now<<1|1,mid+1,tr);
    191     }
    192 }
    193 
    194 void work(){
    195     dfs1(1,0,1);
    196     dfs2(1,1);
    197     build_tree(1,1,n);
    198     for(int i=1;i<=m;i++){
    199     char ch = getchar(); while(ch != '+' && ch != '-') ch = getchar();
    200     int fr,t,w;
    201     if(ch == '+'){
    202         scanf("%d%d%d",&fr,&t,&w);Q[i].from=fr;Q[i].to=t;Q[i].w=w;
    203     }else{
    204         int x; scanf("%d",&x);fr = Q[x].from,t = Q[x].to,w = -Q[x].w;  
    205     }
    206     Modify(fr,t,w);
    207     printf("%lld
    ",Ans.top());
    208     }
    209 }
    210 
    211 int main(){
    212     read();
    213     work();
    214     return 0;
    215 }
  • 相关阅读:
    阅读之分布式架构的数据一致
    阅读之MySQL数据库分表
    阅读笔记1
    问题账户需求分析
    软件需求分析阅读笔记
    开发进度第四天
    开发进度第三天
    开发进度第二天
    线程中三个关键对象闭锁,栅栏,信号量
    java多线程中关于原子操作
  • 原文地址:https://www.cnblogs.com/Menhera/p/9347536.html
Copyright © 2011-2022 走看看