[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\n",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;
}

 

posted @ 2018-09-28 13:37  NewErA  阅读(192)  评论(0编辑  收藏  举报