zoukankan      html  css  js  c++  java
  • 【树链剖分】【函数式权值分块】bzoj1146 [CTSC2008]网络管理Network

    裸题,直接上。复杂度O(n*sqrt(n)*log(n))。

    //Num[i]表示树中的点i在函数式权值分块中对应的点
    //Map[i]表示函数式权值分块中的点i在树中对应的点
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define N 80001
    #define INF 2147483647
    #define NN 87001
    #define BN 296
    int x,y;
    int fa[N],dep[N],siz[N],son[N],Num[N],tot,top[N],n,m,Ks[N],xs[N],ys[N],w[N];
    int en,first[N],next[N<<1],v[N<<1];
    int en2,en3,ma[NN],a[NN];
    int l[BN],sum=1,r[BN],num[N];
    int r2[NN],num2[NN],sum2=1;
    struct Point{int p,v;}t[NN];
    bool operator < (const Point &a,const Point &b){return a.v<b.v;}
    struct Val_Block
    {
        int b[NN],sumv[BN];
        void insert(const int &x){++b[x]; ++sumv[num2[x]];}
        void erase(const int &x){--b[x]; --sumv[num2[x]];}
    }T[285],S;
    void AddEdge(const int &U,const int &V)
    {
        v[++en]=V;
        next[en]=first[U];
        first[U]=en;
    }
    void dfs(int U,int Fa,int d)
    {
        fa[U]=Fa;
        dep[U]=d;
        siz[U]=1;
        for(int i=first[U];i;i=next[i])
          if(v[i]!=fa[U])
            {
              dfs(v[i],U,d+1);
              siz[U]+=siz[v[i]];
              if(siz[v[i]]>siz[son[U]])
                son[U]=v[i];
            }
    }
    void dfs2(int U)
    {
    	if(son[U])
    	  {
    	  	top[son[U]]=top[U];
    	  	Num[son[U]]=++tot;
    	  	dfs2(son[U]);
    	  }
        for(int i=first[U];i;i=next[i])
          if(v[i]!=fa[U]&&v[i]!=son[U])
            {
              top[v[i]]=v[i];
              Num[v[i]]=++tot;
              dfs2(v[i]);
            }
    }
    void makeblock()
    {
        int sz=sqrt(n);
        if(!sz) sz=1;
        for(;sum*sz<n;++sum)
          {
            l[sum]=r[sum-1]+1;
            r[sum]=sum*sz;
            for(int i=l[sum];i<=r[sum];++i)
              num[i]=sum;
          }
        l[sum]=r[sum-1]+1;
        r[sum]=n;
        for(int i=l[sum];i<=r[sum];++i)
          num[i]=sum;
    }
    void val_mb()
    {
        int sz=sqrt(en3);
        if(!sz) sz=1;
        for(;sum2*sz<en3;++sum2)
          {
            r2[sum2]=sum2*sz;
            for(int i=r2[sum2-1]+1;i<=r2[sum2];++i)
              num2[i]=sum2;
          }
        r2[sum2]=en3;
        for(int i=r2[sum2-1]+1;i<=r2[sum2];++i)
          num2[i]=sum2;
    }
    void Init_Ts()
    {
        for(int i=1;i<=sum;++i)
          {
            T[i]=T[i-1];
            for(int j=l[i];j<=r[i];++j)
              T[i].insert(a[j]);
          }
    }
    int Query(const int &x,const int &y,const int &K)
    {
    //构建零散部分的权值分块 
        int U=x,V=y,cnt=0,res=INF;
        int f1=top[U],f2=top[V];
        while(f1!=f2)
          {
            if(dep[f1]<dep[f2])
              {
                swap(U,V);
                swap(f1,f2);
              }
            if(num[Num[f1]]+1>=num[Num[U]])
              for(int i=Num[f1];i<=Num[U];++i)
                S.insert(a[i]);
            else
              {
                for(int i=Num[f1];i<=r[num[Num[f1]]];++i)
                  S.insert(a[i]);
                for(int i=l[num[Num[U]]];i<=Num[U];++i)
                  S.insert(a[i]);
              }
            U=fa[f1];
            f1=top[U];
          }
        if(dep[U]>dep[V])
          swap(U,V);
        if(num[Num[U]]+1>=num[Num[V]])
          for(int i=Num[U];i<=Num[V];++i)
            S.insert(a[i]);
        else
          {
            for(int i=Num[U];i<=r[num[Num[U]]];++i)
              S.insert(a[i]);
            for(int i=l[num[Num[V]]];i<=Num[V];++i)
              S.insert(a[i]);
          }
    //计算答案
        for(int i=sum2;i>=1;--i)
          {
            int tcnt=0;
            U=x; V=y;
            f1=top[U]; f2=top[V];
            while(f1!=f2)
              {
                if(dep[f1]<dep[f2])
                  {
                    swap(U,V);
                    swap(f1,f2);
                  }
                if(num[Num[f1]]+1<num[Num[U]])
                  tcnt+=T[num[Num[U]]-1].sumv[i]-T[num[Num[f1]]].sumv[i];
                U=fa[f1];
                f1=top[U];
              }
            if(dep[U]>dep[V])
              swap(U,V);
            if(num[Num[U]]+1<num[Num[V]])
              tcnt+=T[num[Num[V]]-1].sumv[i]-T[num[Num[U]]].sumv[i];
            tcnt+=S.sumv[i];
            cnt+=tcnt;
            if(cnt>=K)
              {
                cnt-=tcnt;
                for(int j=r2[i];;--j)
                  {
                    U=x; V=y;
                    f1=top[U]; f2=top[V];
                    while(f1!=f2)
                      {
                        if(dep[f1]<dep[f2])
                          {
                            swap(U,V);
                            swap(f1,f2);
                          }
                        if(num[Num[f1]]+1<num[Num[U]])
                          cnt+=T[num[Num[U]]-1].b[j]-T[num[Num[f1]]].b[j];
                        U=fa[f1];
                        f1=top[U];
                      }
                    if(dep[U]>dep[V])
                      swap(U,V);
                    if(num[Num[U]]+1<num[Num[V]])
                      cnt+=T[num[Num[V]]-1].b[j]-T[num[Num[U]]].b[j];
                    cnt+=S.b[j];
                    if(cnt>=K)
                      {
                        res=j;
                        goto OUT;
                      }
                  }
              }
          }
        OUT:
    //清空零散部分的权值分块 
        U=x,V=y;
        f1=top[U],f2=top[V];
        while(f1!=f2)
          {
            if(dep[f1]<dep[f2])
              {
                swap(U,V);
                swap(f1,f2);
              }
            if(num[Num[f1]]+1>=num[Num[U]])
              for(int i=Num[f1];i<=Num[U];++i)
                S.erase(a[i]);
            else
              {
                for(int i=Num[f1];i<=r[num[Num[f1]]];++i)
                  S.erase(a[i]);
                for(int i=l[num[Num[U]]];i<=Num[U];++i)
                  S.erase(a[i]);
              }
            U=fa[f1];
            f1=top[U];
          }
        if(dep[U]>dep[V])
          swap(U,V);
        if(num[Num[U]]+1>=num[Num[V]])
          for(int i=Num[U];i<=Num[V];++i)
            S.erase(a[i]);
        else
          {
            for(int i=Num[U];i<=r[num[Num[U]]];++i)
              S.erase(a[i]);
            for(int i=l[num[Num[V]]];i<=Num[V];++i)
              S.erase(a[i]);
          }
        return res;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        makeblock();
        for(int i=1;i<=n;++i)
          scanf("%d",&w[i]);
        for(int i=1;i<n;++i)
          {
            scanf("%d%d",&x,&y);
            AddEdge(x,y);
            AddEdge(y,x);
          }
        top[1]=1;
        Num[1]=++tot;
        dfs(1,0,1);
        dfs2(1);
        for(int i=1;i<=n;++i)
          {
            t[Num[i]].v=w[i];
            t[Num[i]].p=Num[i];
          }
        en2=n;
        for(int i=1;i<=m;++i)
          {
            scanf("%d%d%d",&Ks[i],&xs[i],&ys[i]);
            if(!Ks[i])
              {
                t[++en2].v=ys[i];
                t[en2].p=en2;
              }
          }
        sort(t+1,t+en2+1);
        ma[a[t[1].p]=++en3]=t[1].v;
        for(int i=2;i<=en2;++i)
          {
            if(t[i].v!=t[i-1].v) ++en3;
            ma[a[t[i].p]=en3]=t[i].v;
          }
        val_mb();
        Init_Ts();
        en2=n;
        for(int i=1;i<=m;++i)
          {
            if(Ks[i])
              {
                int ans=Query(xs[i],ys[i],Ks[i]);
                if(ans==INF) puts("invalid request!");
                else printf("%d
    ",ma[ans]);
              }
            else
              {
                ++en2;
                for(int j=num[Num[xs[i]]];j<=sum;++j)
                  {
                    T[j].erase(a[Num[xs[i]]]);
                    T[j].insert(a[en2]);
                  }
                a[Num[xs[i]]]=a[en2];
              }
          }
        return 0;
    }
  • 相关阅读:
    jdbc连接池中c3p0的配置文件的详解以及在在java中如何使用
    idea导入myeclipes项目、运行项目
    java中身份证号和的银行卡的深度校验
    springBoot的搭建使用记录
    java分模块项目在idea中使用maven打包失败(ps:maven常用到的命令)
    js获取当前页面相关信息
    mybatis使用中的记录
    tomcat服务的启动与隐藏启动(win)
    cmd命令关闭占用程序的端口
    ping端口是否开放(windows,macos,linux)
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/4321431.html
Copyright © 2011-2022 走看看