zoukankan      html  css  js  c++  java
  • [uoj576]服务调度

    先考虑一个子问题:仅有一个询问且无修改

    对每一种颜色的贡献分类讨论,结论:最远的点一定这些点集中(任意一组)最远点对中的两个点(选择较远的一个)

    证明:设$dis(x,y)$为$x$到$y$的距离,$deep_{x}$表示以$k$为根时$x$的深度

    假设这个点集中最远点为$(x,y)$,而最深的点为$z$,且$deep_{z}$严格大于$deep_{x}$和$deep_{y}$

    一个显然的性质:$deep_{lca(x,y)}le deep_{x},deep_{y}$

    考虑$w=lca(x,y,z)$,若$z=w$与$deep_{z}>deep_{x},deep_{y}$矛盾,因此假设$z$在$w$的某个儿子$w_{z}$中

    当若$x$和$y$都在$w_{z}$的子树中显然$lca(x,y,z)$可以为$w_{z}$,因此必然存在一个点在其子树外,不妨设为是$x$,则$lca(x,z)=w$,必然有$deep_{w}le deep_{lca(x,y)}$

    考虑此时$dis(x,z)$与$dis(x,y)$,通过lca的形式展开,由于$deep_{z}>deep_{y}$且$deep_{w}le deep_{lca(x,y)}$,因此$dis(x,z)>dis(x,y)$,与$(x,y)$为最远点对矛盾

    通过合并的方式(即不断插入一个点,三个点两两求$dis$)求出每一个点集的最远点对$(x,y)$,这一部分可以做到$o(nlog_{2}n)$

    进一步的,不妨假设$deep_{x}ge deep_{y}$(此时的$deep$为以1为根),通过倍增找到$z$满足$z$在$x$到$lca(x,y)$的路径上且$dis(x,z)<lceilfrac{dis(x,y)}{2} ceil$中$dis(x,z)$最大,那么$k$满足$dis(k,y)>dis(k,x)$当且仅当$k$在$z$子树中

    特别的,当$x=y$时令$z=x$,这是为了方便处理,证明比较显然,这里就省略了

    接下来,考虑对答案的贡献,分为两部分:

    1.$z$的子树中,点$k$的答案加上$deep_{y}+deep_{k}-2depp_{lca(x,y)}$,首尾两个式子都为常数,线段树+dfs序即可,$deep_{k}$通过打“区间加点深度”的标记,再维护区间内所有点深度和即可处理

    2.$z$的子树外,考虑$deep_{x}+deep_{k}-2deep_{lca(x,k)}$,前两个式子与上面处理方式相同,考虑第三个式子——

    再建一棵线段树,将$fa_{z}$到根的路径打上“减2倍其到父亲的边权”,那么一个点所需要减的就是其到根路径上所有点的和,同时对$z$的子树内部没有影响,因此应对$z$的子树区间加$fa_{z}$的深度

    这个考虑在询问时处理,假设询问$k$的子树,对于$k$到根路径上的所有点都会被减小$k$子树大小次,之后对于$k$子树内部的点会被减小子树大小次

    分别维护这个值以及这个值乘对应子树大小的两颗线段树就可以处理了,另外链修改需要树链剖分,总复杂度为$o(nlog^{2}n)$

    (注意,这样两颗线段树是独立的,也就是对两边的贡献用不同的方式计算)

    对于修改,可以看作在某种颜色中插入/删除一个点,对于插入同样直径合并(之后重新修改),删除可以用线段树来做,同样利用直径合并的性质就可以做了(注意修改完直径后都要重新计算贡献)

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 200005
      4 #define ll long long
      5 #define L (k<<1)
      6 #define R (L+1)
      7 #define mid (l+r>>1)
      8 #define pii pair<int,int>
      9 #define fi first
     10 #define se second
     11 struct ji{
     12     int nex,to,len;
     13 }edge[N];
     14 int E,n,m,t,x,p,a[N],head[N],d1[N],d2[N],sz[N],son[N],dfn[N],inv_dfn[N],top[N],fa[N][21];
     15 int V,pos[N],rt[N],ls[N*40],rs[N*40];
     16 vector<int>v[N];
     17 pii fd[N*40];
     18 ll val[4][N<<2],tag[4][N<<2],f[4][N<<2];
     19 void add(int x,int y,int z){
     20     edge[E].nex=head[x];
     21     edge[E].to=y;
     22     edge[E].len=z;
     23     head[x]=E++;
     24 }
     25 void dfs1(int k,int s1,int s2){
     26     d1[k]=s1;
     27     d2[k]=s2;
     28     sz[k]=1;
     29     for(int i=1;i<=20;i++)fa[k][i]=fa[fa[k][i-1]][i-1];
     30     for(int i=head[k];i!=-1;i=edge[i].nex)
     31         if (edge[i].to!=fa[k][0]){
     32             dfs1(edge[i].to,s1+1,s2+edge[i].len);
     33             sz[k]+=sz[edge[i].to];
     34             if ((!son[k])||(sz[son[k]]<sz[edge[i].to]))son[k]=edge[i].to;
     35         }
     36 }
     37 void dfs2(int k,int t){
     38     dfn[k]=++x;
     39     inv_dfn[x]=k;
     40     top[k]=t;
     41     if (son[k])dfs2(son[k],t);
     42     for(int i=head[k];i!=-1;i=edge[i].nex){
     43         int u=edge[i].to;
     44         if ((u!=fa[k][0])&&(u!=son[k]))dfs2(u,u);
     45     }
     46 }
     47 int lca(int x,int y){
     48     if (d1[x]<d1[y])swap(x,y);
     49     for(int i=20;i>=0;i--)
     50         if (d1[fa[x][i]]>=d1[y])x=fa[x][i];
     51     if (x==y)return x;
     52     for(int i=20;i>=0;i--)
     53         if (fa[x][i]!=fa[y][i]){
     54             x=fa[x][i];
     55             y=fa[y][i];
     56         }
     57     return fa[x][0];
     58 }
     59 int dis(int x,int y){
     60     if ((!x)||(!y))return 0;
     61     return d2[x]+d2[y]-2*d2[lca(x,y)];
     62 }
     63 pii merge(pii x,pii y){
     64     int d=0,a[5];
     65     pair<int,int>ans=make_pair(0,0);
     66     a[0]=0;
     67     if (x.fi)a[++a[0]]=x.fi;
     68     if (x.se)a[++a[0]]=x.se;
     69     if (y.fi)a[++a[0]]=y.fi;
     70     if (y.se)a[++a[0]]=y.se;
     71     if (a[0]==1)return make_pair(a[1],0);
     72     for(int i=1;i<=a[0];i++)
     73         for(int j=i+1;j<=a[0];j++){
     74             int dd=dis(a[i],a[j]);
     75             if (dd>d){
     76                 d=dd;
     77                 ans=make_pair(a[i],a[j]);
     78             }
     79         }
     80     return ans;
     81 }
     82 void update(int &k,int l,int r,int x,int y){
     83     if (!k)k=++V;
     84     if (l==r){
     85         fd[k]=make_pair(y,0);
     86         return;
     87     }
     88     if (x<=mid)update(ls[k],l,mid,x,y);
     89     else update(rs[k],mid+1,r,x,y);
     90     fd[k]=merge(fd[ls[k]],fd[rs[k]]);
     91 }
     92 void up(int k){
     93     for(int i=0;i<4;i++)f[i][k]=f[i][L]+f[i][R];
     94 }
     95 void upd(int p,int k,int x){
     96     tag[p][k]+=x;
     97     f[p][k]+=x*val[p][k];
     98 }
     99 void down(int k){
    100     for(int i=0;i<4;i++)
    101         if (tag[i][k]){
    102             upd(i,L,tag[i][k]);
    103             upd(i,R,tag[i][k]);
    104             tag[i][k]=0;
    105         }
    106 }
    107 void build(int k,int l,int r){
    108     if (l==r){
    109         x=inv_dfn[l];
    110         val[0][k]=1;
    111         val[1][k]=d2[x];
    112         if (x==1)val[2][k]=0;
    113         else val[2][k]=d2[x]-d2[fa[x][0]];
    114         val[3][k]=val[2][k]*sz[x];
    115         return;
    116     }
    117     build(L,l,mid);
    118     build(R,mid+1,r);
    119     for(int i=0;i<4;i++)val[i][k]=val[i][L]+val[i][R];
    120 }
    121 void update(int p,int k,int l,int r,int x,int y,int z){
    122     if ((l>y)||(x>r))return;
    123     if ((x<=l)&&(r<=y)){
    124         upd(p,k,z);
    125         return;
    126     }
    127     down(k);
    128     update(p,L,l,mid,x,y,z);
    129     update(p,R,mid+1,r,x,y,z);
    130     up(k);
    131 }
    132 ll query(int p,int k,int l,int r,int x,int y){
    133     if ((l>y)||(x>r))return 0;
    134     if ((x<=l)&&(r<=y))return f[p][k];
    135     down(k);
    136     return query(p,L,l,mid,x,y)+query(p,R,mid+1,r,x,y);
    137 }
    138 void calc(int k,int p){
    139     int x=fd[rt[k]].fi,y=fd[rt[k]].se;
    140     if (!x)return;
    141     int z;
    142     if (!y)z=y=x;
    143     else{
    144         if (d2[x]<d2[y])swap(x,y);
    145         z=x;
    146         int d=(dis(x,y)+1)/2;
    147         for(int i=20;i>=0;i--)
    148             if (d2[x]-d2[fa[z][i]]<d)z=fa[z][i];
    149     }
    150     update(0,1,1,n,dfn[z],dfn[z]+sz[z]-1,p*(d2[y]-2*d2[lca(x,y)]));
    151     update(0,1,1,n,1,dfn[z]-1,p*d2[x]);
    152     update(0,1,1,n,dfn[z]+sz[z],n,p*d2[x]);
    153     update(1,1,1,n,1,n,p);
    154     update(0,1,1,n,dfn[z],dfn[z]+sz[z]-1,2*p*d2[fa[z][0]]);
    155     z=fa[z][0];
    156     while (z>1){
    157         update(2,1,1,n,dfn[top[z]],dfn[z],-2*p);
    158         update(3,1,1,n,dfn[top[z]],dfn[z],-2*p);
    159         z=fa[top[z]][0];
    160     }
    161 }
    162 ll query(int k){
    163     ll ans=0;
    164     for(int i=0;i<4;i++)
    165         if (i!=2)ans+=query(i,1,1,n,dfn[k],dfn[k]+sz[k]-1);
    166     int x=sz[k];
    167     k=fa[k][0];
    168     while (k>1){
    169         ans+=x*query(2,1,1,n,dfn[top[k]],dfn[k]);
    170         k=fa[top[k]][0];
    171     }
    172     return ans;
    173 }
    174 int main(){
    175     scanf("%d%d%d",&n,&t,&m);
    176     for(int i=1;i<=n;i++){
    177         scanf("%d",&a[i]);
    178         v[a[i]].push_back(i);
    179         pos[i]=v[a[i]].size();
    180     }
    181     memset(head,-1,sizeof(head));
    182     fa[1][0]=1;
    183     for(int i=2;i<=n;i++)scanf("%d",&fa[i][0]);
    184     for(int i=2;i<=n;i++){
    185         scanf("%d",&x);
    186         add(fa[i][0],i,x);
    187     }
    188     dfs1(1,0,0);
    189     x=0;
    190     dfs2(1,1);
    191     build(1,1,n);
    192     for(int i=1;i<=n;i++)update(rt[a[i]],1,n+m,pos[i],i);
    193     for(int i=1;i<=t;i++)calc(i,1);
    194     for(int i=1;i<=m;i++){
    195         scanf("%d%d",&p,&x);
    196         if (p==2)printf("%lld
    ",query(x));
    197         else{
    198             calc(a[x],-1);
    199             update(rt[a[x]],1,n+m,pos[x],0);
    200             calc(a[x],1);
    201             scanf("%d",&a[x]);
    202             calc(a[x],-1);
    203             v[a[x]].push_back(x);
    204             pos[x]=v[a[x]].size();
    205             update(rt[a[x]],1,n+m,pos[x],x);
    206             calc(a[x],1);
    207         }
    208     }
    209 }
    View Code
  • 相关阅读:
    FFmpeg(二) 解封装相关函数理解
    Android NDK(一) ndk-build构建工具进行NDK开发
    Android NDK(二) CMake构建工具进行NDK开发
    C++学习笔记二、头文件与源文件
    C++学习笔记一
    JNA的步骤、简单实例以及资料整理
    Java异常总结
    UML-类图
    排序六:希尔排序
    排序四:归并排序--分治法
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14244439.html
Copyright © 2011-2022 走看看