bzoj4999: This Problem Is Too Simple!

题面在这里

题意:

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

做法:

树链剖分+动态开点线段树。
每个数值都维护一棵线段树。
不想离散可以用map偷懒。。。

代码:

/*************************************************************
    Problem: bzoj 4999 This Problem Is Too Simple!
    User: fengyuan
    Language: C++
    Result: Accepted
    Time: 5596 ms
    Memory: 245664 kb
    Submit_Time: 2018-01-03 20:45:26
*************************************************************/

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cctype>
#include<map>
#define mid (l+r>>1)
#define lc o<<1
#define rc o<<1|1
using namespace std;
typedef long long LL;

inline LL read()
{
    char ch = getchar(); LL x = 0; int op = 1;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
    for(; isdigit(ch); ch = getchar()) x = x*10 + ch-'0';
    return x*op;
}
inline void writeabs(LL a) { if(a >= 10) writeabs(a/10); putchar(a%10+'0'); }
inline void write(LL a) { if(a < 0) putchar('-'); writeabs(abs(a)); }

const int N = 100010, M = 20000010;
int n, m, total, cnt, clk, all;
int a[N], head[N], depth[N], fa[N], sz[N], son[N], in[N], top[N];
int rt[N<<2], L[M], R[M], sum[M];
char opt[4];
map<int, int> MP;
struct Edge{
    int to, nex;
    Edge() {}
    Edge(int x, int y) { to = x, nex = y; }
}e[N<<1];

inline int get(int x)
{
    if(MP.count(x)) return MP[x];
    MP[x] = ++ all; return all;
}
inline void addEdge(int x, int y) { e[++ cnt] = Edge(y, head[x]); head[x] = cnt; }
inline void dfs(int u, int lst, int s)
{
    depth[u] = s; fa[u] = lst; sz[u] = 1;
    for(int i = head[u]; i; i = e[i].nex){
        int v = e[i].to; if(v == lst) continue;
        dfs(v, u, s+1); sz[u] += sz[v];
        if (sz[v] > sz[son[u]]) son[u] = v;
    }
}
inline void dfs2(int u, int t)
{
    in[u] = ++ clk; top[u] = t;
    if(son[u]) dfs2(son[u], t);
    for(int i = head[u]; i; i = e[i].nex)
        if(e[i].to != son[u] && e[i].to != fa[u]) dfs2(e[i].to, e[i].to);
}
inline void update(int &o, int l, int r, int x, int y)
{
    if(!o) o = ++ total;
    if(l == r) { sum[o] += y; return; }
    if(x <= mid) update(L[o], l, mid, x, y); else update(R[o], mid+1, r, x, y);
    sum[o] = sum[L[o]] + sum[R[o]];
}
inline int getsum(int o, int l, int r, int x, int y)
{
    if(!o) return 0;
    if(l == x && r == y) return sum[o];
    if(y <= mid) return getsum(L[o], l, mid, x, y); else if(x > mid) return getsum(R[o], mid+1, r, x, y);
    else return getsum(L[o], l, mid, x, mid) + getsum(R[o], mid+1, r, mid+1, y);
}
inline int qry(int x, int y, int z)
{
    int ret = 0;
    while(top[x] != top[y]) {
        if(depth[top[x]] < depth[top[y]]) swap(x, y);
        ret += getsum(rt[z], 1, n, in[top[x]], in[x]);
        x = fa[top[x]];
    }
    if(depth[x] > depth[y]) swap(x, y);
    ret += getsum(rt[z], 1, n, in[x], in[y]);
    return ret;
}
int main()
{
    n = read(), m = read();
    for(int i = 1; i <= n; i ++) a[i] = read();
    for(int i = 1; i < n; i ++) {
        int x = read(), y = read();
        addEdge(x, y); addEdge(y, x);
    } dfs(1, 0, 0); dfs2(1, 1);
    for(int i = 1; i <= n; i ++) {
        a[i] = get(a[i]);
        update(rt[a[i]], 1, n, in[i], 1);
    }
    while(m --) {
        scanf("%s", opt); int x = read(), y = read(), z;
        if(opt[0] == 'C') {
            update(rt[a[x]], 1, n, in[x], -1);
            a[x] = get(y);
            update(rt[a[x]], 1, n, in[x], 1);
        } else {
            z = read();
            if(!MP.count(z)) puts("0"); else write(qry(x, y, MP[z])), puts("");
        }
    }
    return 0;
}
发布了162 篇原创文章 · 获赞 28 · 访问量 3万+
展开阅读全文

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

©️2019 CSDN 皮肤主题: 游动-白 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览