【清华集训2016】数据交互
题目描述
一个简单的网络系统可以被描述成一棵无根树。每个节点为一个服务器。连接服务器与服务器的数据 线则看做一
条树边。两个服务器进行数据交互时,数据会经过连接这两个服务器的路径上的所有服务 器(包括这两个服务器
自身)。每个数据交互请求都有一个非负的重要度,越重要的请求显然需要得 到越高的优先处理权。此外,如果
在某一个时刻存在一条非常重要(可以看作重要度无穷大)、且数 据量巨大的交互请求,则所有被该交互经过的
服务器都会优先处理这条交互并阻塞,从而导致其他通 过这些服务器的交互出现延迟。现在,你作为一个网络系
统的管理员,要监控整个系统的运行状态。 系统的运行也很简单,在每一个时刻,只有可能出现下列二种事件中
的一种:
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)]<deep[LCA(x',y')]此时我们应当在
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为路径权值)。
所以我们的前后缀里应当算上一个轻子树的答案。
因为这道题的修改内容比较多,所以我们可以先把该改的内容先改掉,然后在往上依次更新。
对于a类的更新:只有单点改,在线段树上直接改。
对于b类的更新:链上改。
但这样会WA一个点。
我们考虑哪里会漏情况。
我们没有考虑两条来自轻子树的链的拼接情况,所以我们在向上更新的时候要用最长链和次长链更新父节点的dp值。
代码
(调ddp一时爽,一直调一直爽)
#include<iostream>#include
<cstdio>#include
<queue>#define N 100002
usingnamespace std;
typedef longlong 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(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
struct edge{int n,to;}e[N<<1];
inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
struct pq{
priority_queue<ll>q1,q2;
inline void insert(ll x){q1.push(x);}
inline void erase(ll x){q2.push(x);while(!q2.empty()&&q1.top()==q2.top())q1.pop(),q2.pop();}
inline void pop(){q1.pop();while(!q2.empty()&&q1.top()==q2.top())q1.pop(),q2.pop();}
inline ll top(){if(q1.empty())return0;while(!q2.empty()&&q1.top()==q2.top())q1.pop(),q2.pop();return q1.top();}
inline ll ci(){ //care!!!
if(q1.empty())return0;
while(!q2.empty()&&q1.top()==q2.top())q1.pop(),q2.pop();
ll x=q1.top();q1.pop();
while(!q2.empty()&&q1.top()==q2.top())q1.pop(),q2.pop();
if(q1.empty()){q1.push(x);return0;}
ll y=q1.top();q1.push(x);
return y;
}
}s[N],ans;
struct node{
ll lx,rx,sum,ans;
node(){lx=rx=sum=ans=0;}
inline node operator *(const node &b)const{
node res;
res.lx=max(lx,sum+b.lx);//if(res.lx==7)cout<<lx<<" "<<sum<<" "<<b.lx<<"jingle"<<endl;
res.rx=max(b.rx,b.sum+rx);
res.sum=sum+b.sum;
res.ans=max(max(ans,b.ans),rx+b.lx);
return res;
}
};
struct segment_tree{
node tr[N<<2];ll la[N<<2];
inline void od(node &x,ll y){x.ans+=y;x.rx+=y;}
inline void pushdown(int cnt){od(tr[cnt<<1],la[cnt]);od(tr[cnt<<1|1],la[cnt]);la[cnt<<1]+=la[cnt];la[cnt<<1|1]+=la[cnt];la[cnt]=0;}
void upd(int cnt,int l,int r,int L,int R,ll x){
if(l>=L&&r<=R){od(tr[cnt],x);la[cnt]+=x;return;}
int mid=(l+r)>>1;
if(la[cnt])pushdown(cnt);
if(mid>=L)upd(cnt<<1,l,mid,L,R,x);
if(mid<R)upd(cnt<<1|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){
if(l>=L&&r<=R){return tr[cnt];}
int mid=(l+r)>>1;if(la[cnt])pushdown(cnt);
if(mid>=L&&mid<R)return 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(mid<R)return query(cnt<<1|1,mid+1,r,L,R);
}
void upd1(int cnt,int l,int r,int x,ll y,int tag){
if(l==r){
if(tag==2){ll delta=y-ji[lu];ji[lu]=y;tr[cnt].ans+=delta;return;}
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(int u){
size[u]=1;
for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa[u]){
int v=e[i].to;fa[v]=u;deep[v]=deep[u]+1;
dfs1(v);
size[u]+=size[v];
if(size[v]>size[son[u]])son[u]=v;
}
}
void dfs2(int u){
if(!top[u])top[u]=u;dfn[u]=++dfn[0];
ed[top[u]]=u;
if(son[u])top[son[u]]=top[u],dfs2(son[u]);
for(int i=head[u];i;i=e[i].n){
int v=e[i].to;if(v==fa[u]||v==son[u])continue;
s[u].insert(0);
dfs2(v);
}
}
inline int add(int u,int v,ll w){
while(top[u]!=top[v]){
if(deep[top[u]]<deep[top[v]])u^=v^=u^=v;
T.upd(1,1,n,dfn[top[u]],dfn[u],w);
u=fa[top[u]];
}
if(deep[u]>deep[v])u^=v^=u^=v;
if(dfn[u]<dfn[v])T.upd(1,1,n,dfn[u]+1,dfn[v],w);
return u;
}
inline void work(int u){
while(1){
int to=top[u];
node x=T.query(1,1,n,dfn[to],dfn[ed[to]]);
ans.erase(num[to]);
num[to]=x.ans;
ans.insert(num[to]);
int f=fa[to];
if(!f)break;
ll cn=s[f].top();
s[f].erase(lmx[to]);
lmx[to]=x.lx;
s[f].insert(lmx[to]);
cn=s[f].top()-cn;
T.upd1(1,1,n,dfn[f],cn,1);
ll xx=s[f].ci();
lu=f;T.upd1(1,1,n,dfn[f],xx,2);
u=f;
}
}
struct tim{int u,v;ll w;}t[N];
int main(){
n=rd();m=rd();int u,v,tt;ll w;
for(int i=1;i<n;++i){
u=rd();v=rd();
add(u,v);add(v,u);
}
dfs1(1);dfs2(1);
deep[0]=-1;
for(int i=1;i<=n;++i)ans.insert(0);
for(int i=1;i<=m;++i){
scanf("%s",ss);
if(ss[0]=='+'){
u=rd();v=rd();w=rd();
t[i]=tim{u,v,w};
}
else{
tt=rd();
u=t[tt].u;v=t[tt].v;w=-t[tt].w;
}
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】数据交互 的全部内容, 来源链接: utcz.com/z/509329.html