zoukankan      html  css  js  c++  java
  • [BZOJ 3720] Gty的妹子树

    Link:

    BZOJ 3720 传送门

    Solution:

    由于强制在线+新添节点,主席树难以进行更新

    这时考虑在树上分块,具体内部的操作和在序列上相同

    每次通过判断父节点块的大小判断是否要新开一块

    注意每一块在树上都是连续的,这样在查询时子树时保证最后全是整块

    不过由于上一条特性导致遇到菊花图就将每一块大小卡到了1

    复杂度稳定的算法其实是对修改操作进行分块:

    每$sqrt(q)$次修改后就暴力重构主席树,复杂度$O(n*log(n)*sqrt(n))$

    每次查询先找到上次暴力重构的结果,再对之后的$sqrt(q)$次询问用倍增找到其对答案的影响

    这样总复杂度是稳定的$O(n*log(n)*sqrt(n))$

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    #define X first
    #define Y second
    #define pb push_back
    typedef double db;
    typedef long long ll;
    typedef pair<int,int> P;
    const int MAXN=6e4+10,SIZE=305;
    
    struct BLOCK
    {
        int a[310],size;
        void Insert(int x)
        {
            a[++size]=x;
            for(int i=size;i>1;i--)
                if(a[i-1]>a[i]) swap(a[i],a[i-1]);
        }
        void Update(int x,int val)
        {
            int pos=lower_bound(a+1,a+size+1,x)-a;
            a[pos]=val;
            for(int i=pos;i>=2;i--)
                if(a[i-1]>a[i]) swap(a[i],a[i-1]);
            for(int i=pos;i<=size-1;i++)
                if(a[i]>a[i+1]) swap(a[i],a[i+1]);
        }
        int Query(int x)
        {return size-(upper_bound(a+1,a+size+1,x)-a-1);}
    }bl[MAXN];
    struct edge{int nxt,to;}
    e[MAXN<<2],eb[MAXN<<2];
    int n,q,op,x,y,sub[MAXN],w[MAXN],f[MAXN];
    int cnt,tot,totb,head[MAXN],headb[MAXN],res;
    
    inline int read()
    {
        char ch;int num,f=0;
        while(!isdigit(ch=getchar())) f|=(ch=='-');
        num=ch-'0';
        while(isdigit(ch=getchar())) num=num*10+ch-'0';
        return f?-num:num;
    }
    
    void add(int x,int y)
    {e[++tot]=(edge){head[x],y};head[x]=tot;}
    void addb(int x,int y)
    {eb[++totb]=(edge){headb[x],y};headb[x]=totb;}
    
    void dfs(int x,int anc)
    {
        if(bl[sub[anc]].size==SIZE)
        {
            bl[++cnt].Insert(w[x]);
            addb(sub[anc],cnt);sub[x]=cnt;
        }
        else sub[x]=sub[anc],bl[sub[anc]].Insert(w[x]);
        
        for(int i=head[x];i;i=e[i].nxt)
            if(e[i].to!=anc) 
                f[e[i].to]=x,dfs(e[i].to,x);
    }
    int calblock(int x,int val)
    {
        int ret=bl[x].Query(val);
        for(int i=headb[x];i;i=eb[i].nxt)
            ret+=calblock(eb[i].to,val);
        return ret;
    }
    int cal(int x,int val)
    {
        int ret=(w[x]>val);
        for(int i=head[x];i;i=e[i].nxt)
        {
            if(e[i].to==f[x]) continue;
            if(sub[e[i].to]==sub[x]) 
                ret+=cal(e[i].to,val);
            else ret+=calblock(sub[e[i].to],val);
        }
        return ret;
    }
    
    int main()
    {
        n=read();
        for(int i=1;i<n;i++)
            x=read(),y=read(),add(x,y),add(y,x);
        for(int i=1;i<=n;i++) w[i]=read();
        dfs(1,0);
        
        q=read();
        while(q--)
        {
            op=read();x=read();y=read();
            x^=res;y^=res;
            if(op==0)
                printf("%d
    ",res=cal(x,y));
            else if(op==1)
            {
                bl[sub[x]].Update(w[x],y);
                w[x]=y;
            }
            else
            {
                w[++n]=y;f[n]=x;
                add(x,n);add(n,x);
                if(bl[sub[x]].size==SIZE)
                {
                    sub[n]=++cnt;
                    bl[cnt].Insert(y);
                    addb(sub[x],cnt);
                }
                else
                {
                    sub[n]=sub[x];
                    bl[sub[x]].Insert(y);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    9- 遍历map集合的方法
    linux下修改了tomcat端口之后无法访问
    汪汪
    无题
    python之禅
    kettle连接oracle出现Error connecting to database: (using class oracle.jdbc.driver.OracleDriver)
    Android camera
    网站部署,网站要求需要支持mb_substring
    oracle笔记
    CSS jQuery 图片全屏切换
  • 原文地址:https://www.cnblogs.com/newera/p/9718083.html
Copyright © 2011-2022 走看看