洛谷 P2137 Gty的妹子树 时间分块+暴力重构

题目背景

我曾在弦歌之中听过你,

檀板声碎,半出折子戏。

舞榭歌台被风吹去,

岁月深处尚有余音一缕……

Gty神(xian)犇(chong)从来不缺妹子……

他来到了一棵妹子树下,发现每个妹子有一个美丽度……

由于Gty很哲♂学,他只对美丽度大于某个值的妹子感兴趣。

他想知道某个子树中美丽度大于k的妹子个数。

某个妹子的美丽度可能发生变化……

树上可能会出现一只新的妹子……

题目描述

维护一棵初始有n个节点的有根树(根节点为1),树上节点编号为1-n,每个点有一个权值wi。

支持以下操作:

0 u x 询问以u为根的子树中,严格大于x的值的个数。(u^=lastans,x^=lastans)

1 u x 把u节点的权值改成x。(u^=lastans,x^=lastans)

2 u x 添加一个编号为”当前树中节点数+1”的节点,其父节点为u,其权值为x。(u^=lastans,x^=lastans)

最开始时lastans=0。

输入输出格式

输入格式:
输入第一行包括一个正整数n(1<=n<=30000),代表树上的初始节点数。

接下来n-1行,每行2个整数u,v,为树上的一条无向边。

任何时刻,树上的任何权值大于等于0,且两两不同。

接下来1行,包括n个整数wi,表示初始时每个节点的权值。

接下来1行,包括1个整数m(1<=m<=30000),表示操作总数。

接下来m行,每行包括三个整数 op,u,x:

op,u,x的含义见题目描述。

保证题目涉及的所有数在int内。

输出格式:
对每个op=0,输出一行,包括一个整数,意义见题目描述。

输入输出样例

输入样例#1:
2
1 2
10 20
1
0 1 5
输出样例#1:
2
输入样例#2:
2
1 2
10 20
1
0 1 10
输出样例#2:
1
说明

时间限制每个测试点1s

空间限制128M

分析:
我们可以对时间分块,每个节点开一个 v e c t o r 记录子树中的所有数,可以归并维护。对于修改操作(包括连边),开一个栈,先在原来的树中查询,然后再看这些修改连边操作能不能影响答案,也就是判断修改点是否在查询点的子树中,可以开一个st表搞一下。如果栈中的操作大于一个值 c ,那么直接暴力重构这棵树。重构是 n l o g n 的,查询是 l o g n + c 的,所以要把块建得尽量大一点。

代码:

// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>

using namespace std;

const int maxn=6e4+7;
const int maxe=1e5+7;

int n,cnt,test,lastans,block,op,x,y;
int ls[maxn],f[maxn][20],w[maxn],a[maxn],dep[maxn];

vector <int> t[maxn];

struct edge{
    int y,next;
}g[maxe];

struct rec{
    int x,w,pre;
};
vector <rec> q;

void add(int x,int y)
{
    g[++cnt]=(edge){y,ls[x]};
    ls[x]=cnt;
}

void merge(int x,int y)
{
    int l=0,r=0,num=0;
    while ((l<t[x].size()) || (r<t[y].size()))
    {
        if (l>=t[x].size()) a[++num]=t[y][r++];
        else
        {
            if (r>=t[y].size()) a[++num]=t[x][l++];
            else
            {
                if (t[x][l]<t[y][r]) a[++num]=t[x][l++];
                                else a[++num]=t[y][r++];
            }
        }
    }
    t[x].clear();
    for (int i=1;i<=num;i++) t[x].push_back(a[i]);
}

void rebuild(int x,int fa)
{
    if (!f[x][0]) f[x][0]=fa;
    if (!dep[x]) dep[x]=dep[fa]+1;
    t[x].clear();
    t[x].push_back(w[x]);
    for (int i=ls[x];i>0;i=g[i].next)
    {
        int y=g[i].y;
        if (y==fa) continue;
        rebuild(y,x);
        merge(x,y);
    }
}

int query(int x,int k)
{
    if (t[x].empty()) return 0;     
    int l=0,r=t[x].size()-1;
    int sum=0;
    while (l<r)
    {
        int mid=(l+r)/2;
        if (t[x][mid+1]>k) sum+=(r-mid),r=mid;
                      else l=mid+1;
    }
    if (t[x][l]>k) sum++;
    return sum;
}

bool isfather(int x,int y)
{
    if (dep[x]>dep[y]) return 0;
    for (int d=dep[y]-dep[x];d;d-=d&(-d))
    {
        int k=trunc(log((d&(-d))+0.5)/log(2));
        y=f[y][k];
    }
    return (x==y);
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    for (int i=1;i<=n;i++) scanf("%d",&w[i]);       
    rebuild(1,0);       
    for (int j=1;j<20;j++)
    {
        for (int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1];
    }   
    scanf("%d",&test);
    lastans=0;
    block=trunc(sqrt(test*10));
    for (int i=1;i<=test;i++)
    {
        scanf("%d%d%d",&op,&x,&y);      
        x^=lastans; y^=lastans;
        if (op==0)
        {                               
            if (q.size()>block)
            {
                rebuild(1,0);
                q.clear();
            }
            lastans=query(x,y);
            for (int i=0;i<q.size();i++)
            { 
                if (isfather(x,q[i].x))
                {
                    if ((q[i].pre<=y) && (q[i].w>y)) lastans++;
                    if ((q[i].pre>y) && (q[i].w<=y)) lastans--;
                }
            }
            printf("%d\n",lastans);
        }
        if (op==1)
        {
            q.push_back((rec){x,y,w[x]});
            w[x]=y;
        }
        if (op==2)
        {
            n++;
            add(x,n);
            f[n][0]=x;
            dep[n]=dep[x]+1;
            q.push_back((rec){n,y,w[n]});
            w[n]=y;
            for (int j=1;j<20;j++) f[n][j]=f[f[n][j-1]][j-1];
        }
    }   
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/81664300