P4175 [CTSC2008] 网络管理

P4175 [CTSC2008] 网络管理

Solution:

存了半年,骂了半年的树上树套树还是在今天咬着牙写完了真是可恶

首先我们来回顾一下如果不带修的话这题怎么做:对每个点维护一颗主席树,存 rt->u 这条路径上的边的权值。然后对于一个查询 (x,y,k)x+y-lca-fa[lca] 这颗树上查第k大值.

那么我们再来思考一下带修怎么写:首先我们都知道主席树的本质其实是前缀和,如果我们要修改一个点的点权,那么就会牵扯到至多 O(n) 颗树(它的后继)。这样我们就会十分难受,怎么办呢?

还记得当年在学前缀和时老师同时交了另一个东西: 树状数组。我们在建树时,可以不按照线性前缀和,而在树状数组上建树,这样我们在单点修改时只用修改 log2n 个点就好了,这样的时间复杂度就是 O(nlog2n)

Code:

#include<bits/stdc++.h>
const int N=1e6+5;
const int inf=1e8;
const int lg=17;
using namespace std;
inline int lowbit(int x){return x&-x;}
int n,m;
struct Segment_Tree{
struct Tree{
int ls,rs,cnt;
}t[N*40];
int rt[N],cnt;
void insert(int &x,int l,int r,int pos,int k)
{
t[x=(x ? x : ++cnt)].cnt+=k;
if(l==r)return;
int mid=l+r>>1;
if(pos<=mid)insert(t[x].ls,l,mid,pos,k);
if(mid<pos) insert(t[x].rs,mid+1,r,pos,k);
}
void update(int x,int val,int k)
{
for(int u=x;u<=n;u+=lowbit(u))insert(rt[u],1,inf,val,k);
}
int A[N],vis[N],now[N];
int query(int x,int y,int p,int q,int k)
{
for(int u=x;u;u-=lowbit(u)){if(vis[u])continue;A[++A[0]]=u;vis[u]=1;}for(int u=y;u;u-=lowbit(u)){if(vis[u])continue;A[++A[0]]=u;vis[u]=1;}
for(int u=p;u;u-=lowbit(u)){if(vis[u])continue;A[++A[0]]=u;vis[u]=1;}for(int u=q;u;u-=lowbit(u)){if(vis[u])continue;A[++A[0]]=u;vis[u]=1;}
for(int i=1;i<=A[0];i++)now[A[i]]=rt[A[i]];
int l=1,r=inf,ans=0,mid=1+inf>>1,a,b,c,d;
while(l<r)
{
mid=l+r>>1,ans=0;
a=b=c=d=0;
for(int u=x;u;u-=lowbit(u)){a+=t[t[now[u]].ls].cnt;}for(int u=y;u;u-=lowbit(u)){b+=t[t[now[u]].ls].cnt;}
for(int u=p;u;u-=lowbit(u)){c-=t[t[now[u]].ls].cnt;}for(int u=q;u;u-=lowbit(u)){d-=t[t[now[u]].ls].cnt;}
ans=a+b+c+d;
if(ans>=k)
{
for(int i=1;i<=A[0];i++)now[A[i]]=t[now[A[i]]].ls;
r=mid;
}
else
{
k-=ans;
for(int i=1;i<=A[0];i++)now[A[i]]=t[now[A[i]]].rs;
l=mid+1;
}
}
for(int i=A[0];i>=0;i--)vis[A[i]]=0;A[0]=0;
return l;
}
}T;
vector<int> E[N];
int a[N];
int f[N][lg+5];
int dep[N],dfn[N],st[N],ed[N];
void dfs(int x,int fa)
{
dep[x]=dep[fa]+1;f[x][0]=fa;
dfn[++dfn[0]]=x;st[x]=dfn[0];
for(int j=1;j<=lg;j++)f[x][j]=f[f[x][j-1]][j-1];
for(int y : E[x])
{
if(y==fa)continue;
dfs(y,x);
}
ed[x]=dfn[0]+1;
}
int LCA(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
for(int j=lg;j>=0;j--)x = dep[f[x][j]]>=dep[y] ? f[x][j] : x;
if(x==y)return x;
for(int j=lg;j>=0;j--)if(f[x][j]!=f[y][j])x=f[x][j],y=f[y][j];
return f[x][0];
}
struct task{
};
void work()
{
cin>>n>>m;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1,x,y;i<n;i++)
{
scanf("%d%d",&x,&y);
E[x].push_back(y);E[y].push_back(x);
}
dfs(1,0);
for(int i=1;i<=n;i++)
{
T.update(st[i],a[i],1);
T.update(ed[i],a[i],-1);
}
for(int i=1,x,y,k;i<=m;i++)
{
scanf("%d%d%d",&k,&x,&y);
if(!k)
{
T.update(st[x],a[x],-1);
T.update(ed[x],a[x],1);
a[x]=y;
T.update(st[x],a[x],1);
T.update(ed[x],a[x],-1);
}
else
{
int p,q,ans=0;
p=LCA(x,y);q=f[p][0];
k=dep[x]+dep[y]-2*dep[q]-k;
if(k<=0)
{
printf("invalid request!\n");continue;
}
ans=T.query(st[x],st[y],st[p],st[q],k);
printf("%d\n",ans);
}
}
}
int main()
{
//freopen("4.in","r",stdin);freopen("P4175.out","w",stdout);
work();
return 0;
}
posted @   liuboom  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示