1. 程式人生 > 其它 >CodeForces-1076E Vasya and a Tree

CodeForces-1076E Vasya and a Tree

CodeForces - 1076E

Problem Description:

Vasya has a tree consisting of n vertices with root in vertex 1. At first all vertices has 0 written on it.

Let d(i,j) be the distance between vertices i and j, i.e. number of edges in the shortest path from i to j. Also, let's denote k-subtree of vertex x — set of vertices y such that next two conditions are met:
  x is the ancestor of y (each vertex is the ancestor of itself);    d(x,y)≤k. Vasya needs you to process m queries. The i-th query is a triple vi, di and xi. For each query Vasya adds value xi to each vertex from di-subtree of vi. Report to Vasya all values, written on vertices of the tree after processing all queries.

Input:

The first line contains single integer n (1≤n≤3105) — number of vertices in the tree.

Each of next n−1 lines contains two integers x and y (1≤x,y≤n) — edge between vertices x and y. It is guarantied that given graph is a tree.

Next line contains single integer m (1≤m≤3105) — number of queries.

Each of next m lines contains three integers vi, di, xi (
1≤vi≤n, 0≤di≤109, 1≤xi≤109) — description of the i-th query.

Output:

Print n integers. The i-th integers is the value, written in the i-th vertex after processing all queries.

  這道題是個樹上查分應該是比較好看出來的(盡管我看了很久),差分我就不YY了,主要是用什麼來維護區間修改。

  方法也是比較多的,有大佬再加了一個差分(詳見 gushui部落格),也有大佬用樹狀陣列(詳見 zqs部落格),更有大佬用線段樹(這位大佬沒有寫部落格,所以沒有連結)。但是,差分和樹狀陣列都要跑兩邊DFS,還要二分一下,線段樹碼量大,而且以上方法都帶log,是O(n log n)的。

  下面我來YY一哈O(n)的線性做法:

  首先讀入圖 和 詢問,然後我們開始DFS,需要記一個類似於Lasy標記的東西(Code中的V[]),可以求出Ans(詳見程式碼)。

  ("O2+O3+fread" 跑得飛快,200ms)

  Code:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
int n,m,Deep[300005],Cnt,Head[300005],Next[600005],To[600005];
long long V[300005],Ans[300005];
struct node {int Deep,V;}A[300005];
vector<node>Q[300005];
#define gc (p1==p2&&(p2=(p1=buf)+fread(buf,1,65536,stdin),p1==p2)?EOF:*p1++)
char buf[65536],*p1,*p2;
inline int read()
{
    char ch;int x(0);
    while((ch=gc)<48);
    do x=x*10+ch-48;while((ch=gc)>=48);
    return x;
}
inline void ADD(int x,int y) {Next[++Cnt]=Head[x],Head[x]=Cnt,To[Cnt]=y,Next[++Cnt]=Head[y],Head[y]=Cnt,To[Cnt]=x;}
inline void DFS(int x,int fa,long long Sum)
{
    Sum+=V[Deep[x]];
    for(register int i=0;i<(int)Q[x].size();++i)
    {
        Sum+=Q[x][i].V;
        if(Deep[x]+Q[x][i].Deep+1<=n) V[Deep[x]+Q[x][i].Deep+1]-=Q[x][i].V;
    }
    Ans[x]=Sum;
    for(register int i=Head[x],j;i;i=Next[i])
    {
        j=To[i];
        if(j==fa) continue;
        Deep[j]=Deep[x]+1,DFS(j,x,Sum);
    }
    for(register int i=0;i<(int)Q[x].size();++i)
        if(Deep[x]+Q[x][i].Deep+1<=n) V[Deep[x]+Q[x][i].Deep+1]+=Q[x][i].V;
}
int main()
{
    n=read();
    for(register int i=1,x,y;i<n;++i) x=read(),y=read(),ADD(x,y);
    m=read();
    for(register int i=1,x,y,z;i<=m;++i) x=read(),y=read(),z=read(),Q[x].push_back(node{y,z});
    Deep[1]=1,DFS(1,0,0);
    for(register int i=1;i<=n;++i) printf("%lld ",Ans[i]);
    return 0;
}
View Code