題目描述
乙個簡單的網路系統可以被描述成一棵無根樹。每個節點為乙個伺服器。連線伺服器與伺服器的資料 線則看做一
條樹邊。兩個伺服器進行資料互動時,資料會經過連線這兩個伺服器的路徑上的所有服務 器(包括這兩個伺服器
自身)。每個資料互動請求都有乙個非負的重要度,越重要的請求顯然需要得 到越高的優先處理權。此外,如果
在某乙個時刻存在一條非常重要(可以看作重要度無窮大)、且數 據量巨大的互動請求,則所有被該互動經過的
伺服器都會優先處理這條互動並阻塞,從而導致其他通 過這些伺服器的互動出現延遲。現在,你作為乙個網路系
統的管理員,要監控整個系統的執行狀態。 系統的執行也很簡單,在每乙個時刻,只有可能出現下列二種事件中
的一種:
1、在某兩個伺服器之間出現一條新的資料互動請求;
2、某個資料互動請求結束;
我們假設這些事件中的互動請求的資料量都足夠小。你的任務是在每乙個時刻的事件結束後,求出:
如果突然出現一條非常重要、且資料量巨大的互動請求
那麼因其造成延遲的資料互動請求的重要度之和最大可能是多少?
題解
題目是要求:動態維護一些鏈的集合,每次操作後都要找出一條鏈,使得和它相交的所有鏈的權值和最大。
假設我們已經選擇了一條鏈xy,那麼我們可以把和它有交的所有鏈分為三種型別。
1、lca(x',y')=lca(x,y)這時我們應當在lca(x,y)處貢獻一次。
2、deep[lca(x,y)]>deep[lca(x',y')]此時我們也應該在lca(x,y)處貢獻一次。
3、deep[lca(x,y)]綜上,我們可以維護兩個陣列a,b,對於一條鏈x',y'我們在非lca的地方將b[i]+=w,lca處將a[i]+=w。
那麼我們選擇的鏈的權值為這條鏈上a之和+b[lca],因為我們a統計的是lca在當前的點上的鏈的貢獻,b統計的是lca不在當前鏈上的貢獻。
然後我們可以發現我們完成這部轉化之後問題就變成了最大子段和問題。
因為它是帶修改的,我們可以考慮使用動態dp。
對於最大子段和問題,我們一般的dp思路是記乙個最大字首,乙個最大字尾,子段和和最大子段。
這道題也一樣。
但我們的最大字尾因為涉及到b類的問題,所以這個字尾是帶著b的。
因為我們發現答案為g[u]+g[v]+w(u,v)+b[u](u和v在一條重鏈上,g為輕子樹的最長字首,w為路徑權值)。
所以我們的前字尾裡應當算上乙個輕子樹的答案。
因為這道題的修改內容比較多,所以我們可以先把該改的內容先改掉,然後在往上依次更新。
對於b類的更新:鏈上改。
但這樣會wa乙個點。
我們考慮**會漏情況。
我們沒有考慮兩條來自輕子樹的鏈的拼接情況,所以我們在向上更新的時候要用最長鏈和次長鏈更新父節點的dp值。
**(調ddp一時爽,一直調一直爽)
#include#include#include
#define n 100002
using
namespace
std;
typedef
long
long
ll;int
tot,head[n],size[n],fa[n],deep[n],top[n],dfn[n],son[n],n,m,ed[n],lu;
ll num[n],lmx[n],ji[n];
char ss[1
];inline ll rd()
while(isdigit(c))
return f?-x:x;
}struct edgee[n<<1
];inline
void add(int u,int v)
struct
pq inline
void erase(ll x)
inline
void pop()
inline ll top()
inline ll ci()
ll y=q1.top();q1.push(x);
return
y; }
}s[n],ans;
struct
node
inline node
operator *(const node &b)const
};struct
segment_tree
inline
void pushdown(int cnt)
void upd(int cnt,int l,int r,int l,int
r,ll x)
int mid=(l+r)>>1
;
if(la[cnt])pushdown(cnt);
if(mid>=l)upd(cnt<<1
,l,mid,l,r,x);
if(mid1|1,mid+1
,r,l,r,x);
tr[cnt]=tr[cnt<<1]*tr[cnt<<1|1
]; }
node query(
int cnt,int l,int r,int l,int
r)
int mid=(l+r)>>1;if
(la[cnt])pushdown(cnt);
if(mid>=l&&midreturn query(cnt<<1,l,mid,l,r)*query(cnt<<1|1,mid+1
,r,l,r);
if(mid>=l)return query(cnt<<1
,l,mid,l,r);
if(midreturn query(cnt<<1|1,mid+1
,r,l,r);
}void upd1(int cnt,int l,int r,int x,ll y,int
tag)
tr[cnt].lx+=y;tr[cnt].rx+=y;tr[cnt].ans+=y;
if(!tag)tr[cnt].sum+=y;
return
; }
int mid=(l+r)>>1;if
(la[cnt])pushdown(cnt);
if(mid>=x)upd1(cnt<<1,l,mid,x,y,tag);else upd1(cnt<<1|1,mid+1
,r,x,y,tag);
tr[cnt]=tr[cnt<<1]*tr[cnt<<1|1
]; }
}t;void dfs1(intu)}
void dfs2(intu)}
inline
int add(int u,int
v,ll w)
if(deep[u]>deep[v])u^=v^=u^=v;
if(dfn[u]1,1,n,dfn[u]+1
,dfn[v],w);
returnu;}
inline
void work(intu)}
struct timt[n];
intmain()
dfs1(
1);dfs2(1
); deep[
0]=-1
;
for(int i=1;i<=n;++i)ans.insert(0
);
for(int i=1;i<=m;++i);
}else
int l=add(u,v,w);
t.upd1(
1,1,n,dfn[l],w,0
); work(u);work(v);
printf(
"%lld\n
",ans.top());
}return0;
}
清華集訓2016 汽水
試題描述 牛牛來到了乙個盛產汽水的國度旅行。這個國度的地圖上有n個城市,這些城市之間用 n 1 條道路連線,任意兩個城市之間,都存在一條路徑連線。這些城市生產的汽水有許多不同的風味,在經過道路 i 時,牛牛會喝掉 wi 的汽水。牛牛非常喜歡喝汽水,但過量地用汽水是有害健康的,因此,他希望在他旅行的這...
清華集訓2016Day4
用盧卡斯定理可知滿足條件即將 n 和 m 分別用 k 進製表示,要求 n 的每一位都要大於等於 m 的對應位。直接數字 dp 設 f 表示處理到第 i 位,n 是否觸上界,m 是否觸上界時的方案數。複雜度 o t log kn include include includeusing namespa...
UOJ276 清華集訓2016 汽水
link 先點分治,儲存下以當前重心為一端且不經過其它中重心的路徑,並按 overline w k 排序。然後二分答案,用雙指標掃每個重心的路徑,並維護下 overline w k 最小的路徑。注意不能選來自同一子樹的兩條路徑,因此我們再維護乙個與 overline w k 最小的路徑來自不同子樹的...