[BZOJ]4999: This Problem Is Too Simple! 树链剖分

Description

给您一颗树,每个节点有个初始值。
现在支持以下两种操作:
1. C i x(0<=x<2^31) 表示将i节点的值改为x。
2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点。

题解:

首先将询问离线,将所有值进行离散化,最多有300000个值,每个值开一个线段树(动态开点),然后树链剖分即可。我犯的错误:搞混原树的编号和新编号。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100010;
const int maxq=200010;
const int MAXN=9000010;
struct Edge{int y,next;}e[maxn*2];
int last[maxn],len=0;
int n,Q;
int ll;
int s[MAXN],lc[MAXN],rc[MAXN],u,val[maxn];
void ins(int x,int y)
{
    int t=++len;
    e[t].y=y;e[t].next=last[x];last[x]=t;
}
struct Ask{int op,x,y,z;}q[maxq];
struct A{int x,id;}a[maxn+maxq];
bool cmp(A x,A y){return x.x<y.x;}
int fa[maxn],dep[maxn],top[maxn],son[maxn],tot[maxn],ys[maxn],Z=0;
void ins(int &now,int l,int r,int pos,int x)
{
    if(!now)now=++u;
    s[now]+=x;
    if(l==r)return;
    int mid=l+r>>1;
    if(pos<=mid)ins(lc[now],l,mid,pos,x);
    else ins(rc[now],mid+1,r,pos,x);
}
int query(int now,int l,int r,int ll,int rr)//ll,rr为now的管辖范围 
{
    if(!s[now])return 0;
    if(l<=ll&&rr<=r)return s[now];
    int mid=ll+rr>>1;
    if(r<=mid)return query(lc[now],l,r,ll,mid);
    else if(l>mid)return query(rc[now],l,r,mid+1,rr);
    else return query(lc[now],l,mid,ll,mid)+query(rc[now],mid+1,r,mid+1,rr);
}
void dfs1(int x)
{
    son[x]=0;tot[x]=1;
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(y!=fa[x])
        {
            fa[y]=x;
            dep[y]=dep[x]+1;
            dfs1(y);
            tot[x]+=tot[y];
            if(tot[y]>tot[son[x]])son[x]=y;
        }
    }
}
void dfs2(int x,int tp)
{
    ys[x]=++Z;top[x]=tp;
    if(son[x])dfs2(son[x],tp);
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(y!=fa[x]&&y!=son[x])dfs2(y,y);
    }
}
void solve(int x,int y,int rt)
{
    int tx=top[x],ty=top[y],ans=0;
    while(tx!=ty)
    {
        if(dep[tx]<dep[ty])swap(tx,ty),swap(x,y);
        ans+=query(rt,ys[tx],ys[x],1,n);
        x=fa[tx];tx=top[x];
    }
    if(dep[x]>dep[y])swap(x,y);
    printf("%d\n",ans+query(rt,ys[x],ys[y],1,n));
}
int main()
{
    scanf("%d%d",&n,&Q);
    for(int i=1;i<=n;i++)scanf("%d",&a[i].x),a[i].id=i;
    ll=n;
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        ins(x,y);ins(y,x);
    }
    for(int i=1;i<=Q;i++)
    {
        char str[3];
        scanf("%s%d%d",str,&q[i].x,&q[i].y);ll++;
        if(str[0]=='C')q[i].op=1,a[ll].id=i+n,a[ll].x=q[i].y,q[i].z=-1;
        else q[i].op=2,scanf("%d",&q[i].z),a[ll].id=i+n,a[ll].x=q[i].z;
    }
    sort(a+1,a+1+ll,cmp);
    int d=0;a[0].x=-1;
    for(int i=1;i<=ll;i++)
    {
        if(a[i].x!=a[i-1].x)d++;
        if(a[i].id<=n)val[a[i].id]=d;
        else
        {
            if(q[a[i].id-n].z==-1)q[a[i].id-n].y=d;
            else q[a[i].id-n].z=d;
        }
    }
    fa[1]=0;dep[1]=1;dfs1(1);
    dfs2(1,1);
    u=d;
    for(int i=1;i<=n;i++)ins(val[i],1,n,ys[i],1);
    for(int i=1;i<=Q;i++)
    {
        if(q[i].op==1)
        {
            ins(val[q[i].x],1,n,ys[q[i].x],-1);
            val[q[i].x]=q[i].y;
            ins(val[q[i].x],1,n,ys[q[i].x],1);
        }
        else solve(q[i].x,q[i].y,q[i].z);
    }
}
发布了476 篇原创文章 · 获赞 461 · 访问量 9万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览