BZOJ 4999: This Problem Is Too Simple! DFS序 + LCA + 树状数组 + 离线

Description

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

Input

第一行有两个整数N,Q(1 ≤N≤ 100,000;1 ≤Q≤ 200,000),分别表示节点个数和操作个数。
下面一行N个整数,表示初始时每个节点的初始值。
接下来N-1行,每行两个整数x,y,表示x节点与y节点之间有边直接相连(描述一颗树)。
接下来Q行,每行表示一个操作,操作的描述已经在题目描述中给出。
 

Output

对于每个Q输出单独一行表示所求的答案。
 
题解:这个做法,有点牵强吧.

感觉像是空间不够闲着蛋疼才会这么去做.

离线也不是很高级.

对每种颜色建立一个基于 DFS 序的树状数组,权值代表的是一个点出现该颜色的次数.

我们想要查询两点间出现该颜色的次数,只需提取出 DFS 序中对应两点间路径即可.

可是由于空间不够用,只能按照所有颜色分类,依次离线处理一遍.

写起来挺麻烦的......
#include<bits/stdc++.h>
#define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout) 
#define maxn 300000 
using namespace std;
struct OPT
{
    int type; 
    int a,b,c,tag;
    OPT(int type=0,int a=0,int b=0,int c=0,int tag=0):type(type),a(a),b(b),c(c),tag(tag){} 
}opt[maxn]; 
vector<OPT>G[maxn]; 
struct BIT
{
    #define N 300000 
    int C[maxn]; 
    int lowbit(int t)
    {
        return t & (-t); 
    }
    void update(int x,int delta)
    {
        while(x<N) 
        {
            C[x]+=delta; 
            x+=lowbit(x); 
        }
    }
    int query(int x)
    {
        int tmp=0;
        while(x>0)
        {
            tmp+=C[x]; 
            x-=lowbit(x); 
        }
        return tmp; 
    }
}tree; 
char str[10]; 
int n,Q,edges,tot,tim,mkk=0;  
int col[maxn],Arr[maxn],hd[maxn],to[maxn<<1],nex[maxn<<1],dfn[maxn],ln[maxn],st[maxn],ed[maxn]; 
int siz[maxn],hson[maxn],dep[maxn],top[maxn],fa[maxn],answer[maxn]; 
void add(int u,int v)
{
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; 
} 
void dfs1(int u,int ff)
{
    ln[++tim]=u,dfn[u]=st[u]=tim,siz[u]=1,dep[u]=dep[ff]+1,fa[u]=ff;  
    for(int i=hd[u];i;i=nex[i])
    {
        int v=to[i];
        if(v==ff) continue; 
        dfs1(v,u); 
        siz[u]+=siz[v]; 
        if(siz[v]>siz[hson[u]]) hson[u]=v; 
    }
    ed[u]=tim; 
} 
void dfs2(int u,int tp)
{
    top[u]=tp; 
    if(hson[u]) dfs2(hson[u],tp); 
    for(int i=hd[u];i;i=nex[i])
    {
        int v=to[i];
        if(v==fa[u]||v==hson[u]) continue; 
        dfs2(v,v); 
    } 
}
int LCA(int x,int y)
{     
    while(top[x]^top[y]) dep[top[x]] > dep[top[y]] ? x = fa[top[x]] : y = fa[top[y]];
    return dep[x]<dep[y]?x:y;  
}
void solve(int cur)
{
    for(int i=0,sz=G[cur].size();i<sz;++i)
    {
        OPT cn=G[cur][i];
        switch(cn.type)
        {
            case -1: 
            {
                int u=cn.a; 
                tree.update(st[u], -1); 
                tree.update(ed[u]+1, +1);
                break;  
            }
            case 1 : 
            {
                int u=cn.a; 
                tree.update(st[u], 1); 
                tree.update(ed[u]+1, -1); 
                break; 
            }
            case 2 : 
            {
                int u=cn.a;
                int v=cn.b;
                int c=cn.c;
                int g=cn.tag; 
                int lca = LCA(u,v);  
                answer[g]=tree.query(dfn[u])+tree.query(dfn[v])-tree.query(dfn[lca])-tree.query(dfn[fa[lca]]); 
                break; 
            }
        }
    }
    for(int i=0,sz=G[cur].size();i<sz;++i)
    {
        OPT cn=G[cur][i]; 
        if(cn.type==-1) tree.update(st[cn.a], +1), tree.update(ed[cn.a]+1,-1); 
        if(cn.type==1)  tree.update(st[cn.a], -1), tree.update(ed[cn.a]+1, +1); 
    }
}
int main()
{
    // setIO("input");     
    scanf("%d%d",&n,&Q);
    for(int i=1;i<=n;++i) scanf("%d",&col[i]),Arr[++tot]=col[i];          
    for(int i=1;i<n;++i)
    {
        int x,y; 
        scanf("%d%d",&x,&y); 
        add(x,y), add(y,x); 
    }
    dfs1(1,0); 
    dfs2(1,1);  
    for(int i=1;i<=Q;++i)
    {
        scanf("%s",str); 
        switch(str[0])
        {
            case 'C' :
            {
                opt[i].type=1; 
                scanf("%d%d",&opt[i].a,&opt[i].b);
                Arr[++tot]=opt[i].b; 
                break;  
            }
            case 'Q' :
            {
                opt[i].type=2; 
                scanf("%d%d%d",&opt[i].a,&opt[i].b,&opt[i].c);
                Arr[++tot]=opt[i].c;  
                break; 
            }
        }
    }
    sort(Arr+1,Arr+1+tot);  
    for(int i=1;i<=Q;++i) 
    {
        if(opt[i].type==1) opt[i].b=lower_bound(Arr+1,Arr+1+tot,opt[i].b)-Arr;
        if(opt[i].type==2) opt[i].c=lower_bound(Arr+1,Arr+1+tot,opt[i].c)-Arr; 
    }  
    for(int i=1;i<=n;++i) 
    {
        col[i]=lower_bound(Arr+1,Arr+1+tot,col[i])-Arr;
        G[col[i]].push_back(OPT(1,i,0,0,0)); 
    }
    for(int i=1;i<=Q;++i)
    {
        if(opt[i].type==2)
        {
            OPT P=opt[i]; 
            P.tag=++mkk; 
            G[opt[i].c].push_back(P);
        } 
        else 
        { 
            int u=opt[i].a,v=opt[i].b;
            G[col[u]].push_back(OPT(-1,u,0,0,0)); 
            G[v].push_back(OPT(1,u,0,0,0));
            col[u]=v;  
        }
    }     
    for(int i=1;i<maxn;++i) 
    {
        if(G[i].size()) solve(i); 
    }
    for(int i=1;i<=mkk;++i) 
    {   
        printf("%d\n",answer[i]); 
    }
    return 0; 
}

  

posted @ 2019-06-13 14:28  EM-LGH  阅读(250)  评论(0编辑  收藏  举报