[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;
}
全部评论

相关推荐

offerboyyyy:之前看到降温完收到offer了的呢佬,可以签保底等
点赞 评论 收藏
分享
牛客569470950号:也不知道是哪个群体45年前鬼哭狼嚎的为自己争取的被剥削的权利
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务