BZOJ 1146 CTSC2008网络管理

82 篇文章 0 订阅
8 篇文章 0 订阅

Problem

BZOJ权限题。。
良心洛谷

Solution

话说刚开始写了个链剖,发现复杂度是 O(nlog3n) O ( n l o g 3 n ) ,有点方就全删了,后来题解说连log^4的splay都A掉了
然后写了个树上主席树,发现复杂度搞错了,又重写了,才改成现在这个样子。。荒废了一上午qwqqq

说正经的吧,就是动态查询路径上权值第k大。
首先我们考虑树上主席树,那么答案统计还是sum[x]+sum[y]-sum[lca]-sum[f[lca]]。我们会发现如果更新了一个点权,则其子树内的所有主席树都要更新,更新的复杂度是 O(nlogn) O ( n l o g n ) ,这显然是承受不起的,其实有80分
注意到子树在dfs序中是成段的,那么我们不妨考虑维护dfs序。则问题变成了区间更新和单点查询,套路差分,就可以转化为单点更新和区间查询,上BIT模板。
时间复杂度 O(nlog2n) O ( n l o g 2 n )

不过在dfs序上,其实这个前缀并不是完全都是到根节点的路径,因为可能有之前搜到的其他子树,但是其实这个对我们统计答案的方式并无影响,因为sum[x]和sum[y]分别对这些冗余信息计算了一次,而sum[lca]和sum[f[lca]]却又分别减去了它们的贡献。
另外注意在update时不必每次访问都重新开节点,不然会MLE。因为这个节点并没有与新节点冲突,除了sum要修改之外,其他信息仍然可以利用。

Code

#include <algorithm>
#include <cstdio>
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int maxn=80010,maxm=10000010;
struct data{int v,nxt;}edge[maxn<<1];
struct operation{int k,a,b;}opr[maxn];
int n,m,p,dfc,tot,len,cnt[2],tmp[2][40];
int head[maxn],a[maxn],b[maxn<<1],f[maxn][20],deep[maxn],pre[maxn],nxt[maxn];
int rt[maxn],lc[maxm],rc[maxm],sum[maxm];
template <typename Tp> inline void read(Tp &x)
{
    x=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
inline void insert(int u,int v)
{
    edge[++p]=(data){v,head[u]};head[u]=p;
    edge[++p]=(data){u,head[v]};head[v]=p;
}
void input()
{
    int k,x,y;
    read(n);read(m);len=n;
    for(int i=1;i<=n;i++){read(a[i]);b[i]=a[i];}
    for(int i=1;i<n;i++){read(x);read(y);insert(x,y);}
    for(int i=1;i<=m;i++)
    {
        read(opr[i].k);read(opr[i].a);read(opr[i].b);
        if(!opr[i].k) b[++len]=opr[i].b;
    }
    sort(b+1,b+len+1);len=unique(b+1,b+len+1)-b-1;
    for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+len+1,a[i])-b;
}
void update(int l,int r,int pos,int val,int& rt)
{
    if(!rt) rt=++tot;
    sum[rt]+=val;
    if(l==r) return ;
    int m=(l+r)>>1;
    if(pos<=m) update(l,m,pos,val,lc[rt]);
    else update(m+1,r,pos,val,rc[rt]);
}
int query(int l,int r,int k)
{
    if(l==r) return l;
    int m=(l+r)>>1,s=0;
    for(int i=1;i<=cnt[0];i++) s+=sum[lc[tmp[0][i]]];
    for(int i=1;i<=cnt[1];i++) s-=sum[lc[tmp[1][i]]];
    if(k<=s)
    {
        for(int i=1;i<=cnt[0];i++) tmp[0][i]=lc[tmp[0][i]];
        for(int i=1;i<=cnt[1];i++) tmp[1][i]=lc[tmp[1][i]];
        return query(l,m,k);
    }
    else
    {
        for(int i=1;i<=cnt[0];i++) tmp[0][i]=rc[tmp[0][i]];
        for(int i=1;i<=cnt[1];i++) tmp[1][i]=rc[tmp[1][i]];
        return query(m+1,r,k-s);
    }
}
void dfs(int x)
{
    for(int i=1;i<20;i++) f[x][i]=f[f[x][i-1]][i-1];
    deep[x]=deep[f[x][0]]+1;pre[x]=++dfc;
    for(int i=head[x];i;i=edge[i].nxt)
      if(edge[i].v!=f[x][0])
      {
        f[edge[i].v][0]=x;
        dfs(edge[i].v);
      }
    nxt[x]=dfc;
}
int getlca(int x,int y)
{
    if(deep[x]<deep[y]) swap(x,y);
    int t=deep[x]-deep[y];
    for(int i=0;i<20;i++)
      if(t&(1<<i)) x=f[x][i];
    if(x==y) return x;
    for(int i=19;~i;i--)
      if(f[x][i]!=f[y][i])
        x=f[x][i],y=f[y][i];
    return f[x][0];
}
void change(int pos,int val,int op)
{
    for(;pos<=n;pos+=lowbit(pos)) update(1,len,val,op,rt[pos]);
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    int x,y,k,lca,flca,s;
    input();dfs(1);
    for(int i=1;i<=n;i++) change(pre[i],a[i],1),change(nxt[i]+1,a[i],-1);
    for(int i=1;i<=m;i++)
    {
        x=opr[i].a;y=opr[i].b;k=opr[i].k;
        if(k)
        {
            lca=getlca(x,y);flca=f[lca][0];cnt[0]=cnt[1]=0;
            s=deep[x]+deep[y]-deep[lca]-deep[flca];
            for(int i=pre[x];i;i-=lowbit(i)) tmp[0][++cnt[0]]=rt[i];
            for(int i=pre[y];i;i-=lowbit(i)) tmp[0][++cnt[0]]=rt[i];
            for(int i=pre[lca];i;i-=lowbit(i)) tmp[1][++cnt[1]]=rt[i];
            for(int i=pre[flca];i;i-=lowbit(i)) tmp[1][++cnt[1]]=rt[i];
            if(k>s) puts("invalid request!");
            else printf("%d\n",b[query(1,len,s-k+1)]);
        }
        else
        {
            change(pre[x],a[x],-1);change(nxt[x]+1,a[x],1);
            a[x]=lower_bound(b+1,b+len+1,y)-b;
            change(pre[x],a[x],1);change(nxt[x]+1,a[x],-1);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值