[T3] 2019.7.25 NOIP игра моделирования дерево (дерево) (ДФС последовательность на дереве открытого сегмента)

Нет операция изменения корневого

Рассмотрим, если нет никакой операции изменения корня, как мы делаем.

Мы можем найти оригинальное дерево \ (ДФС \) последовательность, а затем раскрыть содержание дерева линии.

Для ИЗМЕНЯЮТ работы, мы можем найти множитель \ (ЛКА \) , то измененное значение отрезка дерева поддерева.

Для операций дознаний, мы напрямую запросить значение в поддереве.

Но с операцией изменения корня, \ (LCA \) больше не может быть оригинальным \ (LCA \) , к югу от дерева он больше не может быть оригинальным поддерево.

После операции изменения корневой \ (ЛКА \)

Обращая волна + найти закон, мы можем найти корни \ (RT \) , операцию после изменения корневой \ (LCA (х, у) \) обычно попадают в последующем обсуждении , которое следует :( \ ( х, у \) являются взаимозаменяемыми эмпатия)

  • Если \ (RT \) в \ (Х \) в пределах суб-дерева, и \ (Y \) также \ (Х \) в пределах суб-дерева, \ (ДМС \) является \ (ДМС (у, г , ) \ ) .
  • Если \ (RT \) в \ (Х \) в пределах суб-дерева, \ (Y \) не \ (Х \) в пределах суб-дерева, \ (ДМС \) является \ (Х \) .
  • Если \ (Х \) в \ (RT \) в пределах суб-дерева, и \ (Y \) не \ (RT \) в пределах суб-дерева, \ (ДМС \) является \ (RT \) .
  • Удаление выше, при условии \ (ДМС = Т (Х, Y) \) , если \ (RT \) не \ (Т \) в пределах суб-дерева, \ (ДМС \) является \ (Т \) .
  • В противном случае, пусть \ (Т1 = ДМС (Х, РТ), то LCA Т2 = (У, РТ) \) , \ (ДМС \) является \ (Т1 \) и \ (Т2 \) в большей глубине.

Это не очень сложно?

После операции изменения корня поддерева

Это соотношение \ (LCA \) сознание более, обсуждаются только два случая.

Если \ (к.т. \) не \ (Х \) в суб-дерево, обработка \ (х \) суб-дерево.

В противном случае, мы находим \ (к.т. \) в \ (х \) в суб-дерево , которое его сын, а затем справиться с остальными деревьями в дополнение к югу от дерева. В самом деле, \ (ДФС \) в течение периода префиксов и суффиксов последовательности.

В дополнении к этим двум случаям, однако, есть частный случай следует отметить , что \ (х = к.т. \) , то процесс всего дерева.

код

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 300000
#define LN 20
#define LL long long
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
#define swap(x,y) (x^=y^=x^=y)
using namespace std;
int n,Qt,rt=1,ee,lnk[N+5];LL a[N+5];struct edge {int to,nxt;}e[N<<1];
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define pc(c) (C==E&&(clear(),0),*C++=c)
        #define tn (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        int f,T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    public:
        I FastIO() {A=B=FI,C=FO,E=FO+FS;}
        Tp I void read(Ty& x) {x=0,f=1;W(!D) f=c^'-'?1:-1;W(x=tn+(c&15),D);x*=f;}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
        Tp I void write(Ty x) {x<0&&(pc('-'),x=-x);W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
        Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
        I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
template<int SZ> class SegmentTree//线段树
{
    private:
        #define L l,mid,rt<<1
        #define R mid+1,r,rt<<1|1
        #define PU(x) (V[x]=V[x<<1]+V[x<<1|1])
        #define PD(x,ls,rs) F[x]&&(U(x<<1,F[x],ls),U(x<<1|1,F[x],rs),F[x]=0)
        #define U(x,v,s) (V[x]+=1LL*(s)*v,F[x]+=v)
        int n;LL V[N<<2],F[N<<2];
        I void Build(LL *a,int *fac,CI l,CI r,CI rt)//建树
        {
            if(l==r) return (void)(V[rt]=a[fac[l]]);RI mid=l+r>>1;
            Build(a,fac,L),Build(a,fac,R),PU(rt);
        }
        I void Upt(CI tl,CI tr,CI tv,CI l,CI r,CI rt)//区间修改
        {
            if(tl<=l&&r<=tr) return (void)U(rt,tv,r-l+1);RI mid=l+r>>1;PD(rt,mid-l+1,r-mid);
            tl<=mid&&(Upt(tl,tr,tv,L),0),tr>mid&&(Upt(tl,tr,tv,R),0),PU(rt);
        }
        I LL Qry(CI tl,CI tr,CI l,CI r,CI rt)//区间询问
        {
            if(tl<=l&&r<=tr) return V[rt];RI mid=l+r>>1;PD(rt,mid-l+1,r-mid);
            return (tl<=mid?Qry(tl,tr,L):0)+(tr>mid?Qry(tl,tr,R):0);
        }
    public:
        I void Init(CI _n,LL *a,int *fac) {Build(a,fac,1,n=_n,1);}
        I void Upt(CI l,CI r,CI v) {l<=r&&(Upt(l,r,v,1,n,1),0);}
        I LL Qry(CI l,CI r) {return l<=r?Qry(l,r,1,n,1):0;}
};
class DfnSolver//dfs序列上开线段树
{
    private:
        #define Include(x,y) (dfn[x]<=dfn[y]&&dfn[y]<=dfn[x]+Sz[x]-1)
        int d,dep[N+5],fa[N+5][LN+5],Sz[N+5],dfn[N+5],fac[N+5];SegmentTree<N> S;
        I void dfs(CI x=1)//dfs求出dfs序
        {
            RI i;for(fac[dfn[x]=++d]=x,i=1;i<=LN;++i) fa[x][i]=fa[fa[x][i-1]][i-1];//预处理倍增祖先
            for(Sz[x]=1,i=lnk[x];i;i=e[i].nxt) e[i].to^fa[x][0]&&
                (dep[e[i].to]=dep[fa[e[i].to][0]=x]+1,dfs(e[i].to),Sz[x]+=Sz[e[i].to]);
        }
        I int LCA(RI x,RI y)//倍增求LCA
        {
            RI i;for(dep[x]<dep[y]&&swap(x,y),i=0;dep[x]^dep[y];++i) (dep[x]^dep[y])>>i&1&&(x=fa[x][i]);
            if(x==y) return x;for(i=LN;~i;--i) fa[x][i]^fa[y][i]&&(x=fa[x][i],y=fa[y][i]);return fa[x][0];
        }
        I int GetLCA(CI x,CI y)//求出换根操作后的LCA,分类讨论
        {
            if(Include(x,rt)) return Include(x,y)?LCA(y,rt):x;
            if(Include(y,rt)) return Include(y,x)?LCA(x,rt):y;
            if(Include(rt,x)^Include(rt,y)) return rt;
            RI t=LCA(x,y);if(!Include(t,rt)) return t;
            RI t1=LCA(x,rt),t2=LCA(y,rt);return dep[t1]>dep[t2]?t1:t2;
        }
        I int Jump(RI x,RI d) {for(RI i=0;dep[x]^d;++i) (dep[x]^d)>>i&1&&(x=fa[x][i]);return x;}//树上倍增,跳到对应深度
        I void Upt(CI x,CI v)//修改子树
        {
            if(x==rt) return S.Upt(1,n,v);if(!Include(x,rt)) return S.Upt(dfn[x],dfn[x]+Sz[x]-1,v);
            RI k=Jump(rt,dep[x]+1);S.Upt(1,dfn[k]-1,v),S.Upt(dfn[k]+Sz[k],n,v);
        }
        I LL Qry(CI x)//询问子树
        {
            if(x==rt) return S.Qry(1,n);if(!Include(x,rt)) return S.Qry(dfn[x],dfn[x]+Sz[x]-1);
            RI k=Jump(rt,dep[x]+1);return S.Qry(1,dfn[k]-1)+S.Qry(dfn[k]+Sz[k],n);
        }
    public:
        I void Solve()
        {
            dfs(),S.Init(n,a,fac);RI op,x,y,v;
            W(Qt--) switch(F.read(op,x),op)//读入操作并处理
            {
                case 1:rt=x;break;
                case 2:F.read(y,v),Upt(GetLCA(x,y),v);break;
                case 3:F.writeln(Qry(x));break;
            }
        }
}T;
int main()
{
    freopen("tree.in","r",stdin),freopen("tree.out","w",stdout);
    RI i,x,y;for(F.read(n,Qt),i=1;i<=n;++i) F.read(a[i]);
    for(i=1;i^n;++i) F.read(x,y),add(x,y),add(y,x);return T.Solve(),F.clear(),0;
}

рекомендация

отwww.cnblogs.com/chenxiaoran666/p/Contest20190725T3.html