zoukankan      html  css  js  c++  java
  • 【BZOJ-3052】糖果公园 树上带修莫队算法

    3052: [wc2013]糖果公园

    Time Limit: 200 Sec  Memory Limit: 512 MB
    Submit: 883  Solved: 419
    [Submit][Status][Discuss]

    Description

    Input

    Output

    Sample Input

    Sample Output

    84
    131
    27
    84

    HINT


    Source

    Solution

    树上带修莫队

    本质还是树上莫队,详情可以转 BZOJ-3757苹果树

    但是这里需要修改,就需要一些特殊的地方

    首先DFS对树分块,没什么区别,只不过这里分块可以分得大一些,跑得快

    把一个询问看成一个三元组$(a,b,t)$,$t$是询问的时间,这样对询问排序的时候,就是三关键字

    然后在处理询问的时候,暴力处理修改,不过处理要分情况,如果经过则先对结果进行修改再修改数值,否则直接修改即可

    并不是很详细,还是直接看VFleaKing的讲解吧ORZ VFK

    启发:

    莫队算法不仅可以处理不带修,同样可以处理带修的问题 (似乎还可以处理强制在线的?奇怪的姿势??)

    分块的技巧有很多,应该根据实际情况去选择适合的块的大小

    树上莫队的大体思路都比较类似,实际实现起来也非常像,遇到类似的问题可以如此考虑

    平常得多做一些难写难调的花式题,使得码力++多看看神犇们的解题报告似乎是个不错的事

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    #define maxn 100010
    #define maxm 100010
    #define maxq 100010
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,m,Q,fk,knum,rt[maxn];long long V[maxm],W[maxn],an[maxn],C[maxn],ans;
    struct Edgenode{int to,next;}edge[maxn<<1];
    int head[maxn],cnt;
    void add(int u,int v)
    {cnt++;edge[cnt].next=head[u];head[u]=cnt;edge[cnt].to=v;}
    void insert(int u,int v)
    {add(u,v);add(v,u);}
    int stack[maxn],top,dfsx,dfs[maxn],deep[maxn],father[maxn][25];
    int DFS(int now)
    {
        int size=0;
        dfs[now]=++dfsx;
        for (int i=1; i<=20; i++)
            if (deep[now]>=(1<<i)) father[now][i]=father[father[now][i-1]][i-1];
        for (int i=head[now]; i; i=edge[i].next)
            if (edge[i].to!=father[now][0])
                {
                    deep[edge[i].to]=deep[now]+1;
                    father[edge[i].to][0]=now;
                    size+=DFS(edge[i].to);
                    if (size>=fk)
                        {
                            knum++;
                            for (int j=1; j<=size; j++) rt[stack[top--]]=knum;
                            size=0;
                        }
                }
        stack[++top]=now;
        return size+1;            
    }
    int LCA(int x,int y)
    {
        if (deep[x]<deep[y]) swap(x,y);
        int dd=deep[x]-deep[y];
        for (int i=0; i<=20; i++)
            if (dd&(1<<i) && dd>=(1<<i)) x=father[x][i];
        for (int i=20; i>=0; i--)
            if (father[x][i]!=father[y][i])
                x=father[x][i],y=father[y][i];
        if (x==y) return x; else return father[x][0];
    }
    bool visit[maxn]; int num[maxn];
    void Reverse(int x)
    {
        if (visit[x]) {visit[x]=0; ans-=W[num[C[x]]]*V[C[x]]; num[C[x]]--;}
            else {visit[x]=1;  num[C[x]]++; ans+=W[num[C[x]]]*V[C[x]];}    
    //    printf("%d
    ",ans);
    }
    void Change(int x,int y)
    {
        if (visit[x]) Reverse(x),C[x]=y,Reverse(x); 
            else C[x]=y;
    }
    void work(int x,int y)
    {
        while (x!=y)
            if (deep[x]>deep[y]) Reverse(x),x=father[x][0];
                else Reverse(y),y=father[y][0];
    }
    struct Asknode
    {
        int a,b,t,id;
        bool operator < (const Asknode & A) const
            {
                if (rt[a]==rt[A.a] && rt[b]==rt[A.b]) return t<A.t;
                    else if (rt[a]==rt[A.a]) return rt[b]<rt[A.b];
                return rt[a]<rt[A.a];
            }
    }q[maxq];int numq;
    struct Changenode{int a,b,t,p;}ch[maxq];int numc,p[maxq];
    int main()
    {
        n=read(),m=read(),Q=read(); fk=pow(n,2.0/3)*0.5;
        for (int i=1; i<=m; i++) V[i]=read();
        for (int i=1; i<=n; i++) W[i]=read();
        for (int u,v,i=1; i<=n-1; i++) u=read(),v=read(),insert(u,v);
        for (int i=1; i<=n; i++) C[i]=read();
        for (int i=1; i<=n; i++) p[i]=C[i];
        
        DFS(1); 
    //    puts("OK");
    //    for (int i=1; i<=n; i++) printf("%d %d %d %d
    ",V[i],W[i],dfs[i],p[i]);
    //    for (int i=1; i<=n; i++) printf("%d ",rt[i]); puts("");
    //    puts("OK");
        while (top) rt[stack[top--]]=knum;    
        
        for (int i=1; i<=Q; i++)
            {
                int opt=read(),a=read(),b=read();
                if (opt) {if (dfs[a]>dfs[b]) swap(a,b); numq++;q[numq].a=a; q[numq].b=b; q[numq].t=numc; q[numq].id=numq;}
                    else {numc++;ch[numc].a=a;ch[numc].b=b;ch[numc].t=i;ch[numc].p=p[a]; p[a]=b;}
            }
        sort(q+1,q+numq+1);
        //for (int i=1; i<=numq; i++) printf("%d %d %d %d
    ",q[i].a,q[i].b,q[i].id,q[i].t);
        for (int i=1; i<=q[1].t; i++) Change(ch[i].a,ch[i].b);
        work(q[1].a,q[1].b);
        int T=LCA(q[1].a,q[1].b);
        Reverse(T); an[q[1].id]=ans; Reverse(T);
        for (int i=2; i<=numq; i++)
            {
                for(int j=q[i-1].t+1; j<=q[i].t; j++) Change(ch[j].a,ch[j].b);
                for(int j=q[i-1].t; j>q[i].t; j--) Change(ch[j].a,ch[j].p);
                work(q[i-1].a,q[i].a); work(q[i-1].b,q[i].b);
                T=LCA(q[i].a,q[i].b); Reverse(T); an[q[i].id]=ans; Reverse(T);
            }
        for (int i=1; i<=numq; i++) printf("%lld
    ",an[i]);
        return 0;
    }

    看论文+写+调了一整个上午..1min30s跑完..成功卡住5人评测TAT'' 吐槽一下BZOJ评测机..UOJ上就跑了20s..

  • 相关阅读:
    C#实现函数超出指定时间,自动退出
    批量下载github代码,同时含有解压zip,遍历文件函数
    MSBuild构建工作空间,解决project.Documents.Count()=0的问题
    使用Roslyn 使用MSBuild进行编译,项目不报错,但是运行显示ReflectionTypeLoadException,解决方案
    基于roslyn实现函数与函数之间的依赖关系
    discount C#
    对Symbol的获取(Roslyn)
    AcWing 955. 维护数列(splay插入,删除,区间修改,区间翻转,区间求和,区间求最大子段和)
    AcWing 1063. 永无乡(并查集, 启发式合并,splay)
    AcWing 2437. Splay
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5435228.html
Copyright © 2011-2022 走看看