[luogu4556][Vani有约会]

题目链接

吐槽

这道题调了7个小时也是够了。最后只好比着题解做了一遍2333

思路

首先考虑n=2000的情况。因为这是在一条路径上,所以可以考虑差分。用a[i][j]表示第i个点中j这种粮食出现的次数。加入要在从x到y的路径上加入c这种粮食。将这条路径分为两部分进行差分。从x到lca,也就是将a[x][c]++,a[fa[lca]]--。从y到son[lca]。就是将a[y][c]++,a[lca]--。(详细原因见树上差分)最后dfs一遍,并且在回溯的时候合并一下就行了。

那么对于n=100000的数据,只要用线段树合并优化一下就行了。也就是将a数组改为n棵动态开点线段树。合并的时候用线段树合并的板子合并一下就行了。

代码

/*
* @Author: wxyww
* @Date:   2018-12-10 14:37:11
* @Last Modified time: 2018-12-10 21:15:06
*/
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
#define Ls TR[cur].ls
#define Rs TR[cur].rs
ll read() {
    ll x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}
const int N = 100000 + 100,logN = 20;
struct node {
    int ls,rs,ans,sum;
}TR[N * 50];
int n,m,dep[N],lca[N][logN + 30],root[N];
vector<int>e[N];
int num;
void get_lca(int u,int father) {
    for(int i = 1;i < logN;++i) lca[u][i] = lca[lca[u][i - 1]][i - 1];
    int k = e[u].size();
    for(int i = 0;i < k;++i) {
        int v = e[u][i];
        if(v == father) continue;
        lca[v][0] = u;
        dep[v] = dep[u] + 1;
        get_lca(v,u);
    }
}
int LCA(int x,int y) {
    if(dep[x] < dep[y]) swap(x,y);
    for(int i = logN - 1;i >= 0;--i)
        if(dep[lca[x][i]] >= dep[y]) x = lca[x][i];
    if(x == y) return y;
    for(int i = logN - 1;i >= 0;--i) {
        if(lca[x][i] != lca[y][i]) {
            x = lca[x][i];y = lca[y][i];
        }
    }
    return lca[x][0];
}
void up(int cur) {
    if(TR[Ls].sum >= TR[Rs].sum) {
        TR[cur].sum = TR[Ls].sum;
        TR[cur].ans = TR[Ls].ans;
    }
    else {
        TR[cur].sum = TR[Rs].sum;
        TR[cur].ans = TR[Rs].ans;
    }
}
void update(int &cur,int l,int r,int pos,int c) {
    if(!cur) cur = ++num;
    if(l == r) {
        TR[cur].sum += c;
        TR[cur].ans = l;
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) update(Ls,l,mid,pos,c);
    else update(Rs,mid + 1,r,pos,c);
    up(cur);
}
int merge(int cur,int a,int l,int r) {
    if(!cur) return a;
    if(!a) return cur;
    if(l == r) {
        TR[cur].sum += TR[a].sum;
        TR[cur].ans = l;
        return cur;
    }
    int mid = (l + r) >> 1;
    Ls = merge(Ls,TR[a].ls,l,mid);
    Rs = merge(Rs,TR[a].rs,mid + 1,r);
    up(cur);
    return cur;
}
void dfs(int u,int father) {
    int k = e[u].size();
    for(int i = 0;i < k;++i) {
        int v = e[u][i];
        if(v == father) continue;
        dfs(v,u);
        merge(root[u],root[v],1,N - 100);
    }
}
int main() {
    int n = read(),m = read();
    for(int i = 1;i < n;++i) {
        int x = read(),y = read();
        e[x].push_back(y);
        e[y].push_back(x);
    }
    dep[1] = 1;
    for(int i = 1;i <= n;++i) root[i] = ++num;
    get_lca(1,0);
    while(m--) {
        int x = read(),y = read(),c = read();
        int K = LCA(x,y);
        update(root[x],1,N - 100,c,1);
        update(root[y],1,N - 100,c,1);
        update(root[K],1,N - 100,c,-1);
        if(lca[K][0]) update(root[lca[K][0]],1,N - 100,c,-1);
    }
    dfs(1,0);
    for(int i = 1;i <= n;++i) {
        if(TR[root[i]].sum == 0) puts("0");
        else
        printf("%d\n",TR[root[i]].ans);
    }

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wxyww/p/10099318.html
今日推荐