AcWing 353 rain tail

EDITORIAL

There's no solution to a problem tree cross-section of ......
I'm out of runoff

Title Description

Eri has been deep hate rain.

Hot weather penetrate the first half of the summer, then a heavy rain and consequent flooding, extinguished everything.

Although deep Eri home has a small village on the flood stubborn resistance, but also several old houses collapsed, trees were uprooted trees, and fields of grain are confused mess.

Eri deep frustration and villagers had to wait for relief food to subsist.

But relief food is distributed very special way.

There are n points, form a tree structure.

There payment operation m times, each time selecting two points x, y, for each point on the path from x to y (including x, y) z issuance of a bag type of item.

After the completion of all required payment operations, each point store up to what type of items.

Input format
The first line two positive integers n, m, the meaning of the subject as shown in FIG.

Next, n-1 lines of two numbers (a, b), indicates there is an edge (a, b) between.

The next m lines of three numbers (x, y, z), the meaning of the subject as shown in FIG.

Output formats
total of n rows, an integer i-th row, representing the largest houses in the first i kind of relief food storage, if there are a variety of relief food storage times, like, the smallest output number.

If there are no houses a relief food, a line of output corresponds to 0.

Data range
\ (1 ≦ n, m≤100000 \) ,
\ (1≤z≤10. 9 ^ \)

Sample

SAMPLE INPUT

5 3
1 2
3 1
3 4
5 3
2 3 3
1 5 2
3 3 3

Sample Output

2
3
3
0
2

Algorithm 1

Segment tree merger

There are chiefs have written, I would not bother to go into details


#include <bits/stdc++.h>
#define lson l,mid,tree[now].l
#define rson mid + 1,r,tree[now].r

using namespace std;

const int maxn = 1e5 + 5;
const int maxm = 6e6 + 5;//数组还是 开大点 

int n,m,size,first[maxn],tot,cntz;
int root[maxn],tmp[maxn],top[maxn],cnt[maxn],dep[maxn],father[maxn],ans[maxn];

struct Query{int x,y,z;}ask[maxn];
struct Edge{int v,nt;}edge[maxn << 1];
struct SegMentTree{int l,r,val,id;}tree[maxm]; 
//----------输入输出优化
char *TT,*mo,but[(1 << 18) + 2]; 
#define getchar() ((TT == mo && (mo = ((TT = but) + fread(but, 1, 1 << 18, stdin)),TT == mo)) ? -1 : *TT++) 
template<class T>inline void read(T &x){
    x = 0;bool flag = 0;char ch = getchar();
    while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
    while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
    if(flag) x = -x;
}

template<class T>void putch(const T x){if(x > 9) putch(x / 10);putchar(x % 10 | 48);}
template<class T>void put(const T x){if(x < 0) putchar('-'),putch(-x);else putch(x);}
//---------读入数据 
void eadd(int u,int v){edge[++size].v = v;edge[size].nt = first[u];first[u] = size;}

void readdata(){
    read(n);read(m);
    for(int i = 1;i < n; ++ i){int u,v;read(u);read(v);eadd(u,v);eadd(v,u);}
    for(int i = 1;i <= m; ++ i){read(ask[i].x);read(ask[i].y);read(ask[i].z);tmp[i] = ask[i].z;}
}
//----------LCA
void dfs(int u,int f,int d){
    top[u] = u,dep[u] = d,father[u] = f;cnt[u] = 1;int son = 0,mcnt = 0;
    for(int i = first[u];i;i = edge[i].nt){
        int v = edge[i].v;if(v == f) continue;
        dfs(v,u,d + 1);cnt[u] += cnt[v];
        if(cnt[v]>mcnt) mcnt = cnt[v],son = v;
    }
    if(son) top[son] = u;
}

int find(int x){return top[x] == x ? x : top[x] = find(top[x]);};

int LCA(int x,int y){
    if(find(x) == find(y)) return dep[x] < dep[y] ? x : y;
    else return dep[top[x]] < dep[top[y]] ? LCA(x,father[top[y]]) : LCA(father[top[x]],y);
}
//----------线段树的修改 & 合并 
void pushup(int k){
    int ls = tree[k].l,rs = tree[k].r;
    if(tree[ls].val >= tree[rs].val) tree[k].val = tree[ls].val,tree[k].id = tree[ls].id;
    else tree[k].val = tree[rs].val,tree[k].id = tree[rs].id;
}

void modify(int l,int r,int &now,int pos,int val){
    if(!now) now = ++tot;
    if(l == r && l == pos){tree[now].val += val;tree[now].id = l;return;}
    int mid = (l + r) >> 1;
    if(pos <= mid) modify(lson,pos,val);
    else modify(rson,pos,val);
    pushup(now);//记得pushup 
}

void merge(int &x,int &y,int l,int r){
    if(!x) return;if(!y) {y = x;return;}
    if(l == r){tree[y].val += tree[x].val;return;}
    int mid = (l + r) >> 1;
    merge(tree[x].l,tree[y].l,l,mid);merge(tree[x].r,tree[y].r,mid + 1,r);
    pushup(y);
} 

void merge_dfs(int u,int f){
    for(int i = first[u];i;i = edge[i].nt){
        int v = edge[i].v;if(v == f) continue;//v = edge[i].v
        merge_dfs(v,u);merge(root[v],root[u],1,cntz);
    }
    if(tree[root[u]].val == 0) ans[u] = 0;//当没有救济粮时输出0 
    else ans[u] = tmp[tree[root[u]].id];
}
//---------主模块 
void work(){
    //----------初始化 
    dfs(1,0,1);
    //----------离散化 + 修改 
    sort(tmp + 1,tmp + m + 1);
    cntz = unique(tmp + 1,tmp + m + 1) - (tmp + 1);
    for(int i = 1;i <= m; ++ i){
        ask[i].z = lower_bound(tmp + 1,tmp + cntz+ 1,ask[i].z) - tmp;       
        int lca = LCA(ask[i].x,ask[i].y);
        modify(1,cntz,root[ask[i].x],ask[i].z,1);
        modify(1,cntz,root[ask[i].y],ask[i].z,1);
        modify(1,cntz,root[lca],ask[i].z,-1);
        if(father[lca])modify(1,cntz,root[father[lca]],ask[i].z,-1);
    } 
    //----------合并
    merge_dfs(1,0);
    for(int i = 1;i <= n; ++ i){
        put(ans[i]);putchar('\n');
    }
}

int main(){
    readdata();
    work();
    return 0;
}

Algorithm 2

Chain split tree \ (O (n (log n ) ^ 2) \)

Although it seems to be more a log, but due to the small constant run up faster than the segment merge tree.

Let's recall the tree when the tree section ideological path modification:

The path split into several sections, modify the segment tree

This question also can do

We can modify each split into several sections to do. Because we need to record the type and quantity of relief food, then you need discrete , building a tree line weights to maintain the best value and the corresponding number.

After a split path, because the space is a bit tight this question cards, each point can not build a tree line, so we consider the optimization of space.

In addition to the dynamic open point, we should also be thinking: when the tree section, each point corresponding number is certain, but after asking split, numbering each section is continuous, and the final answer is in all of our requirements after the operation, offline find answers each point.

In general this number is the number of trees in the corresponding section of the tree line, where construction is due to the weight of the tree line, the significance of these numbers it is better understood as a time sequence number.

For modify each successive interval after the split, if the left endpoint sort, then, a point behind the modification interval, will not affect the already finished modifying the points , so we will be able to differential treatment , the number understanding solving in a direct line to the trees time.

For each interval modification \ ([a_i, B_i] \) , or split into at time \ (a_i \) relief grain corresponding to +1 at time \ (b_i + 1 \) relief food corresponding to the - 1, to facilitate the optimization and solution, we can ask each time in a similar way to store the list , each time after solving is complete, you can calculate the answer nodes corresponding.

Such differential modification, and solving the prefix tree line just open a can. And ask about the demolition split into nlogn months.

Sort out ideas:

  1. Initially, a modified path is split into a number of successive interval \ ([a_i, B_i] \) , for each interval is useful as a split differential thought \ (a_i \) + 1'd at a number of val, \ ( B_i \) number at -1 val, each modification able to save each number (time) corresponding to the linked list in a similar manner.

  2. Then, from a traversing all modified numbers and the weights perform a segment tree, then modifying each numbered been traversed, the number of nodes corresponding to the answer recorded (since the differential operation, and this is equivalent to seeking prefix )

C ++ code


#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e5 + 5;

int n,m,size,first[maxn],tot,head[maxn],num,rev[maxn],son[maxn],cntz;//head存询问的“头边” 
int top[maxn],seg[maxn],father[maxn],dep[maxn],cnt[maxn],ans[maxn],tmp[maxn];

struct Edge{int v,nt;}edge[maxn << 1];
struct Query{int x,y,z;}a[maxn];//拆分前的询问
struct Split_Query{int val,nt;}ask[maxn * 20];//拆分后的询问
struct SegmentTree{int val,id;}tree[maxn << 2];
//----------输入输出优化 
//char *TT,*mo,but[(1 << 18) + 2]; 
//#define getchar() ((TT == mo && (mo = ((TT = but) + fread(but, 1, 1 << 18, stdin)),TT == mo)) ? -1 : *TT++) 
template<class T>inline void read(T &x){
    x = 0;
    bool flag = 0;
    char ch = getchar();
    while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
    while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
    if(flag) x = -x;
}
template<class T>void putch(const T x){if(x > 9) putch(x / 10);putchar(x % 10 | 48);}
template<class T>void put(const T x){if(x < 0) putchar('-'),putch(-x);else putch(x);}
//----------读入数据 & 初始化树剖 
void eadd(int u,int v){edge[++size].v = v;edge[size].nt = first[u];first[u] = size;} 

void dfs1(int u,int f){
    father[u] = f;cnt[u] = 1;int mcnt = 0;
    for(int i = first[u];i;i = edge[i].nt){
        int v = edge[i].v;if(v == f) continue;
        dep[v] = dep[u] + 1;dfs1(v,u);cnt[u] += cnt[v];//注意累加 
        if(cnt[v] > mcnt) mcnt = cnt[v],son[u] = v;
    }
}

void dfs2(int u,int f,int tp){
    seg[u] = ++tot;top[u] = tp;rev[seg[u]] = u;
    if(son[u]) dfs2(son[u],u,tp);
    for(int i = first[u];i;i = edge[i].nt){
        int v = edge[i].v;if(v == f || v == son[u]) continue;
        dfs2(v,u,v);
    }
}

void readdata(){
    read(n);read(m);
    for(int i = 1;i < n; ++ i){int u,v;read(u);read(v);eadd(u,v);eadd(v,u);}
    dfs1(1,0);dfs2(1,0,1);
    //离散化 
    for(int i = 1;i <= m; ++ i) read(a[i].x),read(a[i].y),read(a[i].z),tmp[i] = a[i].z;
    sort(tmp + 1,tmp + m + 1);
    cntz = unique(tmp + 1,tmp + m + 1) - (tmp + 1); 
}
//----------拆分修改 
void add_query(int id,int val){ask[++num].val = val;ask[num].nt = head[id];head[id] = num;}

void Split(int x,int y,int z){
    while(top[x] != top[y]){
        if(dep[top[x]] < dep[top[y]]) swap(x,y);
        add_query(seg[top[x]],z);add_query(seg[x] + 1,-z);//top[u]的编号小于u
        x = father[top[x]]; 
    }
    if(dep[x] < dep[y]) swap(x,y);
    add_query(seg[y],z);add_query(seg[x] + 1,-z);
}
//----------线段树模块 
void pushup(int k){
    int ls = k << 1,rs = k << 1 | 1;
    if(tree[ls].val >= tree[rs].val) tree[k].val = tree[ls].val,tree[k].id = tree[ls].id;//>=
    else tree[k].val = tree[rs].val,tree[k].id = tree[rs].id;
}

void modify(int l,int r,int k,int pos,int val){
    if(l == r){tree[k].val += val;tree[k].id = l;return;}
    int mid = (l + r) >> 1;
    if(pos <= mid) modify(l,mid,k<<1,pos,val);
    else modify(mid + 1,r,k<<1|1,pos,val);
    pushup(k);
}
//----------主模块 
void work(){
//----------拆分修改 
    for(int i = 1;i <= m; ++ i) {
        a[i].z = lower_bound(tmp + 1,tmp + 1 + cntz,a[i].z) - tmp; 
        Split(a[i].x,a[i].y,a[i].z);
    }//luogu上似乎不用离散化
//----------修改 
    for(int i = 1;i <= n; ++ i){//这里是seg值,也就是时间 
        for(int j = head[i];j;j = ask[j].nt){
            if(ask[j].val > 0) modify(1,cntz,1,ask[j].val,1);
            else modify(1,cntz,1,-ask[j].val,-1);
        }
        ans[rev[i]] = tree[1].val ? tmp[tree[1].id] : 0;
    }
    for(int i = 1;i <= n; ++ i){
        put(ans[i]);putchar('\n');
    }
}

int main(){
//  freopen("testdata.in","r",stdin);
//  freopen("testdata.out","w",stdout);
    readdata();
    work();
    return 0;
}

Guess you like

Origin www.cnblogs.com/Mandy-H-Y/p/11779289.html
Recommended