树链剖分题单

洛谷大题单传送门

CF916E Jamie and Tree

有换根操作的树链剖分

三种情况
1:u==rt , return tr [1] . sum;
2:u不是rt的祖先,即u不在1->rt这条路径上,无所谓,直接按u为根的子树返回
3:u是rt的祖先,即u在1->rt这条路径上,最特殊的情况
找到路径u->rt上的u的直系儿子v,
就会发现rt为根时,u子树覆盖不到的地方是v及v的子树
然后返回的就是 [ 1, l [v] - 1] + [ r [v] + 1 , n ]
修改区间操作同上

#include<bits/stdc++.h>
using namespace std;
const int N=200010;
typedef long long ll;
int n,m;
struct node
{
    int l,r;
    ll sum,tag;
}tr[N<<2];
int hs[N],sz[N],f[N],dep[N],l[N],r[N],tot,id[N],top[N],fa[N];
ll w[N];
vector<int>e[N];
int rt;

void dfs1(int u,int f)
{
    fa[u]=f;
    hs[u]=-1;
    sz[u]=1;
    dep[u]=dep[f]+1;
    for(auto v: e[u])
    {
        if(v==f) continue;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(hs[u]==-1||sz[v]>sz[hs[u]])
        hs[u]=v;
    }
}

void dfs2(int u,int t)
{
    top[u]=t;
    l[u]=++tot;
    id[tot]=u;
    if(hs[u]!=-1) dfs2(hs[u],t);
    
    for(auto v :e[u] )
    if(v!=hs[u]&&v!=fa[u])
    dfs2(v,v);
    
    r[u]=tot;
}

void pushup(int u)
{
    tr[u].sum=tr[u<<1|1].sum+tr[u<<1].sum;
}

void settag(int u,ll d)
{
    tr[u].sum+=1ll*d*(tr[u].r-tr[u].l+1);
    tr[u].tag+=d;
}

void pushdown(int u)
{
    if(tr[u].tag)
    {
        settag(u<<1,tr[u].tag);
        settag(u<<1|1,tr[u].tag);
        tr[u].tag=0;
    }
}

void build(int u,int l,int r)
{
    if(l==r)
    {
        tr[u]={l,r,w[id[l]],0};
        return ;
    }
    else
    {
        tr[u]={l,r};
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
    }
}

int LCA(int u,int v)
{
    while(top[u]!=top[v])
    {
        if(dep[top[u]]<dep[top[v]]) swap(u,v);
        u=fa[top[u]];
    }
    
    if(dep[u]<dep[v]) return u;
    return v;
}


void modify(int u,int l,int r,int ql,int qr,int d)
{
    if(l>=ql&&r<=qr)
    {
        settag(u,d);
        return ;
    }
    int mid=l+r>>1;
    pushdown(u);
    if(ql<=mid) modify(u<<1,l,mid,ql,qr,d);
    if(qr>mid) modify(u<<1|1,mid+1,r,ql,qr,d);
    pushup(u);
}

int find(int u)
{
   if(u==rt) return -1;
	if(l[u]>=l[rt]||r[u]<l[rt]) return 0;
	int now=rt;//只要找到他的直系儿子v就行了
	while(top[now]!=top[u])
	{
		if(fa[top[now]]==u) return top[now];
		now=fa[top[now]];
	}
	return hs[u];
}

ll query(int u,int l,int r,int ql,int qr)
{
    if(l>=ql&&r<=qr)
    return tr[u].sum;
    else
    {
    int mid=l+r>>1;
    pushdown(u);
    ll ans=0;
    if(ql<=mid) ans+=query(u<<1,l,mid,ql,qr);
    if(qr>mid) ans+=query(u<<1|1,mid+1,r,ql,qr);
    return ans;
    }
}


ll querry_tree(int u)
{
    int bo=find(u);
    if(bo==-1) return tr[1].sum;
	if(bo==0) return query(1,1,n,l[u],r[u]);
	else
	{
		ll ans=query(1,1,n,1,l[bo]-1);
		if(r[bo]+1<=n) ans+=query(1,1,n,r[bo]+1,n);
		return ans;
	}
}

void modify(int u,int d)//分情况讨论
{
    int bo=find(u);//找到换根的编号
    if(bo==-1) modify(1,1,n,1,n,d);
	else if(bo==0) modify(1,1,n,l[u],r[u],d);
	else
	{
	     modify(1,1,n,1,l[bo]-1,d);
		if(r[bo]+1<=n) modify(1,1,n,r[bo]+1,n,d);
	}
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    scanf("%lld",&w[i]);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs1(1,0);
    dfs2(1,1);
    build(1,1,n);
    rt=1;
    for(int i=1;i<=m;i++)
    {
        int op,x,y,d;
        scanf("%d%d",&op,&x);
        if(op==1) rt=x;
        else if(op==2)
        {
            scanf("%d%d",&y,&d);
            int x1=LCA(x,y);
            int y1=LCA(x,rt);
            int z1=LCA(y,rt);
            if(dep[y1]>dep[x1]) x1=y1;
            if(dep[z1]>dep[x1]) x1=z1;
//如果 x,y 都在 r 的子树内,那么LCA 显然为LCA(x,y)。
//如果 x,y 只有一个在 r 的子树内,那么 LCA 肯定为 r。
//如果 x,y 都不在 r 的子树内,我们可以先找到p=LCA(x,r)  q=LCA(y,r)。
//如果 p 和 q 不相同,那么我们选择其中较深的一个;如果 p 和 q 相同,那么LCA 就是 p 或 q.
//综上所述,我们可以发现我们要求的LCA 就是LCA(x,y)LCA(x,r),LCA(y,r) 这三者中深度最大
             modify(x1,d);

            
        }
        else {printf("%lld\n",querry_tree(x));
        }
        
    }
    
    return 0;
}

P2590 树的统计

直接树链剖分线段树维护好了

#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int l[N],r[N],top[N], id[N],fa[N];
int n,m,hs[N],sz[N],dep[N],tot;
vector<int>e[N];
int a[N];
//线段树维护的是dfs序中的节点元素
struct node
{
    int maxn,sum;
}tr[N<<2];

//第一遍dfs 子树大小,重儿子,父亲,深度
void dfs1(int u,int f)
{
    sz[u]=1;
    dep[u]=dep[f]+1;
    hs[u]=-1;
    fa[u]=f;
    for(auto v :e[u])
    {
        if(v==f) continue;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(hs[u]==-1||sz[v]>sz[hs[u]])
        hs[u]=v;
    }
}

//第二遍dfs 每个点的dfs序,重链上的链头元素
void dfs2(int u,int t)
{
    top[u]=t;//记录链头元素t
    l[u]=++tot;
    id[tot]=u;
    if(hs[u]!=-1)//如果有重儿子先遍历重儿子,因为是一条链
    dfs2(hs[u],t);
    
    for(auto v: e[u])
    {
        if(v!=fa[u]&&v!=hs[u])
         dfs2(v,v);//轻儿子的链头是自己
    }
    r[u]=tot;
}

void pushup(int u)
{
    tr[u].maxn=max(tr[u<<1].maxn,tr[u<<1|1].maxn);
    tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}

void build(int u,int l,int r)
{
    if(l==r)
    {
        tr[u]={a[id[l]],a[id[l]]};
        return;
    }
    int mid=l+r>>1;
    build(u<<1,l,mid);
    build(u<<1|1,mid+1,r);
    pushup(u);
}

void update(int u,int l,int r,int p,int x)
{
    if(l==r)
    {
        //l号点,dfs序中第L个点
        tr[u]={x,x};
        return;
    }
    int mid=l+r>>1;
    if(p<=mid)  update(u<<1,l,mid,p,x);
    else update(u<<1|1,mid+1,r,p,x);
    pushup(u);
 }
 
 //[ql,qr]表示需要查询的区间
int querysum(int u,int l,int r,int ql,int qr)
{
    if(l>=ql&&r<=qr) return tr[u].sum;
    else
    {
        int mid=l+r>>1;
        int ans=0;
        if(ql<=mid) ans+=querysum(u<<1,l,mid,ql,qr);
        if(qr>mid)  ans+=querysum(u<<1|1,mid+1,r,ql,qr);
        
        return ans;
     }
}

int querymax(int u,int l,int r,int ql,int qr)
{
    if(l>=ql&&r<=qr) return tr[u].maxn;
    else
    {
        int mid=l+r>>1;
        int ans=-1e9;
        if(ql<=mid) ans=max(ans,querymax(u<<1,l,mid,ql,qr));
        if(qr>mid)  ans=max(ans,querymax(u<<1|1,mid+1,r,ql,qr));
        
        return ans;
     }
}

int qsum(int u,int v)
{
    int ans=0;
    while(top[u]!=top[v])
    {
        if(dep[top[u]]>dep[top[v]]) 
        {
            ans+=querysum(1,1,n,l[top[u]],l[u]);
            u=fa[top[u]];
            
        }else {
             ans+=querysum(1,1,n,l[top[v]],l[v]);
            v=fa[top[v]];
        }
    }
    if (dep[u]<dep[v])swap(u,v);
    ans+=querysum(1,1,n,l[v],l[u]);
    return ans;
}
int qmax(int u,int v)
{
    int ans=-1e9;
    while(top[u]!=top[v])
    {
        if(dep[top[u]]>dep[top[v]]) 
        {
            ans=max(ans,querymax(1,1,n,l[top[u]],l[u]));//
            u=fa[top[u]];
            
        }else {
            ans=max(ans,querymax(1,1,n,l[top[v]],l[v]));
            v=fa[top[v]];
        }
    }
    if (dep[u]<dep[v])swap(u,v);
    ans=max(ans,querymax(1,1,n,l[v],l[u]));
    return ans;
}


// int LCA(int u,int v)
// {
//     while(top[u]!=top[v])
//     {
//         if(dep[top[u]]>dep[top[v]]) u=fa[top[u]];
//         else v=fa[top[v]];
//     }
//     if(dep[u]>dep[v]) return v;
//     else return u;
    
// }

int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int v,u;
        scanf("%d%d",&v,&u);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
    dfs1(1,0);
    dfs2(1,1);
    build(1,1,n);
    scanf("%d",&m);
    
    for(int i=1;i<=m;i++)
    {
        int x,y;
        char op[10];
        scanf("%s%d%d",op,&x,&y);
        if (op[1]=='H')update(1,1,n,l[x],y);
        if (op[1]=='M')printf("%d\n",qmax(x,y));
        if (op[1]=='S')printf("%d\n",qsum(x,y));
        
    }
    return 0;
}

P3313 [SDOI2014]旅行

树链剖分+线段树动态开点
一定是动态开点,如果建10^5的线段树内存早就爆了

#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
typedef long long ll;
int fa[N], sz[N], id[N], hs[N], l[N], r[N], top[N];
int n, m, root[N *20], tot;
int val[N], C[N], dep[N];
int rt;
struct node {
    int l, r;
    int sum, maxn;
} tr[N *20];
vector<int>e[N];

void dfs1(int u, int f) {
    dep[u] = dep[f] + 1;
    hs[u] = -1;
    sz[u] = 1;
    fa[u] = f;

    for (auto v : e[u]) {
        if (v == f)
            continue;

        dfs1(v, u);
        sz[u] += sz[v];

        if (hs[u] == -1 || sz[v] > sz[hs[u]])
            hs[u] = v;
    }
}

void dfs2(int u, int t) {
    top[u] = t;
    l[u] = ++tot;
    id[tot] = u;

    if (hs[u] != -1)
        dfs2(hs[u], t);

    for (auto v : e[u]) {
        if (v != fa[u] && v != hs[u])
            dfs2(v, v);
    }

    r[u] = tot;
}

void pushup(int u) {
    tr[u].sum = tr[tr[u].l].sum + tr[tr[u].r].sum;
    tr[u].maxn = max(tr[tr[u].l].maxn, tr[tr[u].r].maxn);
}


void modify(int &u, int l, int r, int ind, int d) {
    if (!u)
        u = ++rt;

    if (l == r) {
        tr[u].maxn = tr[u].sum = d;
        return ;

    }

    int mid = l + r >> 1;

    if (ind <= mid)
        modify(tr[u].l, l, mid, ind, d);
    else
        modify(tr[u].r, mid + 1, r, ind, d);

    pushup(u);
}

int querys(int u, int l, int r, int ql, int qr) {
    if (ql <= l && r <= qr)
        return tr[u].sum;

    int ans = 0;
    int mid = l + r >> 1;
    
      if(ql<=mid)  ans+=querys(tr[u].l, l, mid, ql, qr);
      if(qr>mid)    ans+=querys(tr[u].r, mid + 1, r, ql, qr);
      return ans;
}

int query2(int u,int l,int r,int ql,int qr)
{
     if (ql <= l && r <= qr)
        return tr[u].maxn;

    int ans = 0;
    int mid = l + r >> 1;
    
      if(ql<=mid)  ans=max(ans,querys(tr[u].l, l, mid, ql, qr));
      if(qr>mid)    ans=max(ans,querys(tr[u].r, mid + 1, r, ql, qr));
      return ans;
}

int  querysum(int u, int v) {
    ll ans = 0;
    int xc = C[v];

    while (top[v] != top[u]) {
        if (dep[top[u]] < dep[top[v]])
            swap(u, v);

        ans += querys(root[xc], 1, tot, l[top[u]], l[u]);
        u = fa[top[u]];
    }

    if (dep[u] < dep[v])
        swap(u, v);

    ans += querys(root[xc], 1, tot, l[v], l[u]);
    return ans;
}

int querymax(int u, int v) {
    int ans = 0;
    int xc = C[v];

    while (top[v] != top[u]) {
        if (dep[top[u]] < dep[top[v]])
            swap(u, v);

        ans = max(ans, query2(root[xc], 1, tot, l[top[u]], l[u]));
        u = fa[top[u]];
    }

    if (dep[u] < dep[v])
        swap(u, v);

    ans = max(ans, query2(root[xc], 1, tot, l[v], l[u]));
    return ans;
}

int main() {

    scanf("%d%d", &n, &m);

    for (int i = 1; i <= n; i++)
        scanf("%d%d", &val[i], &C[i]);

    for (int i = 1; i < n; i++) {
        int v, u;
        scanf("%d%d", &u, &v);
        e[u].push_back(v);
        e[v].push_back(u);
    }

    dfs1(1, 0);
    dfs2(1, 1);

    for (int i = 1; i <= n; i++)
        modify(root[C[i]], 1, tot, l[i], val[i]);

    for (int i = 1; i <= m; i++) {
        char op[10];
        int x, y;
        scanf("%s%d%d", op, &x, &y);

        if (op[0] == 'C' && op[1] == 'C') {
            modify(root[C[x]], 1, tot, l[x], 0);
            C[x] = y;
            modify(root[C[x]], 1, tot, l[x], val[x]);
        }

        if (op[0] == 'C' && op[1] == 'W') {
            val[x] = y;
            modify(root[C[x]], 1, tot, l[x], y);
        }

        if (op[0] == 'Q' && op[1] == 'S')
            printf("%lld\n", querysum(x, y));

        if (op[0] == 'Q' && op[1] == 'M')
            printf("%lld\n", querymax(x, y));

    }

    return 0;
}

P3038 [USACO11DEC]Grass Planting G

树链剖分+线段树
板子题,真的很裸

#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int n,m;
int fa[N],hs[N],sz[N],id[N],l[N],r[N],tot,p[N];
int a[N];
vector<int>e[N];
int dep[N],dis[N];
int top[N];
struct node
{
    int l,r,sum;
    int tag;
}tr[N<<2];

void dfs1(int u,int f)
{
    fa[u]=f;
    dep[u]=dep[f]+1;
    hs[u]=-1;
    sz[u]=1;
    for(auto v : e[u])
    {
        if(v==f) continue;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(hs[u]==-1||sz[u]>sz[hs[u]])
        hs[u]=v;
    }
}

void dfs2(int u,int t)
{
    top[u]=t;
    l[u]=++tot;
    id[tot]=u;
    if(hs[u]!=-1) dfs2(hs[u],t);
    for(auto v : e[u])
     if(v!=fa[u]&&v!=hs[u])
     dfs2(v,v);
     r[u]=tot;
}

void pushup(int u)
{
    tr[u].sum=tr[u<<1|1].sum+tr[u<<1].sum;
}

void build(int u,int l,int r)
{
    tr[u]={l,r};
    if(l==r) 
    {
        tr[u].sum=0;
        return ;
    }
    else
    {
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
    }
}

void settag(int u,int c)
{
    tr[u].sum+=c*(tr[u].r-tr[u].l+1);
    tr[u].tag+=c;
}

void pushdown(int u )
{
    if(tr[u].tag!=0)
    {
        settag(u<<1,tr[u].tag);
        settag(u<<1|1,tr[u].tag);
        tr[u].tag=0;
    }
}


void modify2(int u,int l,int r,int ql,int qr,int d)
{
    if(l>=ql&&r<=qr)
    {
        settag(u,d);
        return ;
    }
    else
    {
        pushdown(u);
        int mid=l+r>>1;
        if(ql <= mid)
            modify2(u<<1,l,mid,ql,qr,d);
        if(qr > mid)
            modify2(u<<1|1,mid+1,r,ql,qr,d);
        pushup(u);
    }
}

void modify(int u,int v)
{
     while(top[u]!=top[v])
    {
        if(dep[top[u]]<dep[top[v]]) swap(u,v);
         modify2(1,1,n,l[top[u]],l[u],1);
         u=fa[top[u]];
    }
    if(dep[u]<dep[v]) swap(u,v);
    modify2(1,1,n,l[v]+1,l[u],1);
}

int query(int u,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr)
    {
        return tr[u].sum;
    }
    else
    {
        pushdown(u);
        int mid=l+r>>1;
        int ans=0;
        if(ql<=mid) ans+=query(u<<1,l,mid,ql,qr);
        if(qr>mid) ans+=query(u<<1|1,mid+1,r,ql,qr);
        return ans;
    }
}


int query(int u,int v)
{
    int ans=0;
    while(top[u]!=top[v])
    {
        if(dep[top[u]]<dep[top[v]]) swap(u,v);
        ans+=query(1,1,n,l[top[u]],l[u]);
        u=fa[top[u]];
        //exit(0);
    }
    if(dep[u]<dep[v]) swap(u,v);
    ans+=query(1,1,n,l[v]+1,l[u]);
    return ans;
}




int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        int v,u,w;
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs1(1,0);
    dfs2(1,1);
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        char op[2];
        int x,y;
        scanf("%s%d%d",op,&x,&y);
        if(op[0]=='P')
        {
            modify(x,y);
        }
        else
        {
            printf("%d\n",query(x,y));
        }
    }
    return 0;
}

P2680 [NOIP2015 提高组] 运输计划

树剖求LCA+二分+树上差分

求最大值中的最小 ,很明显的二分

即二分权值最大的路径的权值最小值,设为mid,只要满足所有路径长度>mid的路径同时减去一条边权后的值<=mid,这个mid就可行,显然,我们减去的这条边必须被所有长度>mid的边都经过,且这条被删去的边要最长。

#include<bits/stdc++.h>
using namespace std;
#define re register
const int N=1000003;
int hs[N],l[N],r[N],fa[N],id[N],p[N];
int dep[N],top[N],tot,a[N],dis[N],sz[N];
vector<pair<int,int>>e[N];
int n,m;
int L,R;
struct node
{
    int x,y,lca,len;
}q[N];
int C[N];


void dfs1(int u,int f)
{
    sz[u]=1;
    dep[u]=dep[f]+1;
    hs[u]=-1;
    fa[u]=f;
    for(auto [v,w] :e[u])
    {
        if(v==f) continue;
        p[v]=w;
        dis[v]=dis[u]+w;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(hs[u]==-1||sz[v]>sz[hs[u]])
        hs[u]=v;
    }
}

void dfs2(int u,int t)
{
    top[u]=t;
    l[u]=++tot;
    id[tot]=u;
    if(hs[u]!=-1)
    dfs2(hs[u],t);
    
    for(auto [v,w]: e[u])
    {
        if(v!=fa[u]&&v!=hs[u])
         dfs2(v,v);
    }
    r[u]=tot;
}
int LCA(int u,int v)
{
    while(top[u]!=top[v])
    {
        if(dep[top[u]]>dep[top[v]]) u=fa[top[u]];
        else v=fa[top[v]];
    }
    if(dep[u]>dep[v]) return v;
    else return u;
    
}

bool check(int mid)
{
    int sum=0;
    memset(C,0,sizeof C);
    for(int i=1;i<=m;i++)
    {
        if(q[i].len>mid)
        {
            C[q[i].x]++,C[q[i].y]++;
            C[q[i].lca]-=2;
            sum++;
        }
    }
    for(re int i=n;i>=1;i--)
    {
       C[fa[id[i]]]+=C[id[i]];//每次差分值都累加到父亲节点
            if(p[id[i]]>=R-mid&&C[id[i]]==sum)
            //存在一条路径满足上述条件则可行
            	return 1;
    }
    return 0;
}




int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        int u,w,v;
        scanf("%d%d%d",&u,&v,&w);
        e[v].push_back({u,w});
        e[u].push_back({v,w});
        L=max(L,w);
    }
    dfs1(1,0);
    dfs2(1,1);
    for(int i=1;i<=m;i++)
    {
        int v,u;
        scanf("%d%d",&v,&u);
        int fas=LCA(u,v);
        int len=dis[u]+dis[v]-2*dis[fas];
        //printf("%d %d %d %d \n",v,u,fas,len);
        q[i]={v,u,fas,len};
        R=max(R,len);
    }
    int ql=R-L , qr =R+1;
    while(ql<qr)
    {
        int mid=ql+qr>>1;
        if(check(mid)) qr=mid;
        else ql=mid+1;
    }
    printf("%d\n",ql);
    
    
    
    return 0;
}

P2146 [NOI2015] 软件包管理器

树链剖分+线段树维护
每次查询时记下上一次的答案,用abs(tr[1].cnt-per)得到答案

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,m,l[N],r[N],top[N],fa[N],hs[N];
int id[N],sz[N];
int w[N],dep[N],tot;
vector<int>e[N];
struct node
{
    int sz;;
    int cnt;
    int t;
}tr[N<<2];


void dfs1(int u,int f)
{
    sz[u]=1;
    hs[u]=-1;
    fa[u]=f;
    dep[u]=dep[f]+1;
    for(auto v : e[u])
    {
        if(v==f) continue;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(hs[u]==-1||sz[v]>sz[hs[u]])
        hs[u]=v;
    }
}

void dfs2(int u,int t)
{
    l[u]=++tot;
    id[tot]=u;
    top[u]=t;
    if(hs[u]!=-1) 
    dfs2(hs[u],t);
    
    for(auto v : e[u])
    {
        if(v!=fa[u]&& v != hs[u] )
         dfs2(v,v);
    }
    
    r[u]=tot;
}
void settag(int u,int t)
{
    if(t==1)
    {
        tr[u].cnt=tr[u].sz;
    }
    else tr[u].cnt=0;
    tr[u].t=t;
}

void update(int u)
{
     tr[u].cnt=tr[u<<1].cnt + tr[u<<1|1].cnt;
}



void pushdown(int u)
{
    if(tr[u].t!=-1)
    {
        settag(u<<1,tr[u].t);
        settag(u<<1|1,tr[u].t);
        tr[u].t=-1;
    }
}

void build(int u,int l,int r)
{
    tr[u].sz=r-l+1;
    tr[u].t=-1;
    
    if(l==r)
    {
    }else
    {
    int mid = l+r >> 1;
    build(u<<1, l  , mid);
    build(u<<1|1, mid+1, r);
    update(u);
    }
}

void modify(int u,int l,int r,int ql,int qr,int c)
{
    if(l==ql&&r==qr)
    {
        settag(u,c);
        return ;
    }
    int mid=l+r >> 1;
    pushdown(u);
    if(qr<=mid) modify(u<<1,l,mid,ql,qr,c);
    else if(ql>mid) modify(u<<1|1,mid+1,r,ql,qr,c);
    else
    {
        modify(u<<1,l,mid,ql,mid,c);
        modify(u<<1|1,mid+1,r,mid+1,qr,c);
    }
    update(u);
}



void install(int x)
{
    while(x!=0)
    {
        modify(1,1,n,l[top[x]],l[x],1);
        x=fa[top[x]];
    }
}

void uninstall(int x)
{
    modify(1,1,n,l[x],r[x],0);
}

int main()
{
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
    {
        scanf("%d",&fa[i]);
        fa[i]++;
        e[fa[i]].push_back(i);
    }
    dfs1(1,0);
    dfs2(1,1);
    build(1,1,n);
    scanf("%d",&m);
    int per=0;
    while(m--)
    {
        int a,b,c;
        char op[10];
        scanf("%s%d",op,&a);
        a++;
        if(op[0]=='i')
        {
            install(a);
           
        }
        else
        {
            uninstall(a);
            // printf("%d \n",abs(per-tr[1].cnt));
        }
            printf("%d \n",abs(per-tr[1].cnt));
            per=tr[1].cnt;
            
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值